remove_definitions(-D_WIN32_WINNT=0x502 -D_WIN32_IE=0x600)
-add_definitions(-DUSE_WINE_TODOS)
+add_definitions(-DUSE_WINE_TODOS -DWINETEST_USE_DBGSTR_LONGLONG)
list(APPEND SOURCE
animate.c
- comboex.c
+ combo.c
datetime.c
dpa.c
+ edit.c
header.c
imagelist.c
ipaddress.c
+ listbox.c
listview.c
misc.c
monthcal.c
progress.c
propsheet.c
rebar.c
+ static.c
status.c
syslink.c
tab.c
set_module_type(comctl32_winetest win32cui)
add_importlibs(comctl32_winetest comctl32 ole32 user32 gdi32 advapi32 msvcrt kernel32)
+
+if(MSVC)
+ add_importlibs(comctl32_winetest ntdll)
+endif()
+
add_pch(comctl32_winetest precomp.h SOURCE)
add_rostests_file(TARGET comctl32_winetest)
--- /dev/null
+/* Unit test suite for ComboBox and ComboBoxEx32 controls.
+ *
+ * Copyright 2005 Jason Edmeades
+ * Copyright 2007 Mikolaj Zalewski
+ *
+ * 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 "precomp.h"
+
+#define EDITBOX_SEQ_INDEX 0
+#define NUM_MSG_SEQUENCES 1
+
+#define EDITBOX_ID 0
+#define COMBO_ID 1995
+
+#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
+
+#define expect_rect(r, _left, _top, _right, _bottom) ok(r.left == _left && r.top == _top && \
+ r.bottom == _bottom && r.right == _right, "Invalid rect %s vs (%d,%d)-(%d,%d)\n", \
+ wine_dbgstr_rect(&r), _left, _top, _right, _bottom);
+
+
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
+
+static HWND hComboExParentWnd, hMainWnd;
+static HINSTANCE hMainHinst;
+static const char ComboExTestClass[] = "ComboExTestClass";
+
+static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
+
+#define MAX_CHARS 100
+static char *textBuffer = NULL;
+
+static BOOL received_end_edit = FALSE;
+
+static void get_combobox_info(HWND hwnd, COMBOBOXINFO *info)
+{
+ BOOL ret;
+
+ info->cbSize = sizeof(*info);
+ ret = GetComboBoxInfo(hwnd, info);
+ ok(ret, "Failed to get combobox info structure, error %d\n", GetLastError());
+}
+
+static HWND createComboEx(DWORD style) {
+ return CreateWindowExA(0, WC_COMBOBOXEXA, NULL, style, 0, 0, 300, 300,
+ hComboExParentWnd, NULL, hMainHinst, NULL);
+}
+
+static LONG addItem(HWND cbex, int idx, const char *text) {
+ COMBOBOXEXITEMA cbexItem;
+ memset(&cbexItem, 0x00, sizeof(cbexItem));
+ cbexItem.mask = CBEIF_TEXT;
+ cbexItem.iItem = idx;
+ cbexItem.pszText = (char*)text;
+ cbexItem.cchTextMax = 0;
+ return SendMessageA(cbex, CBEM_INSERTITEMA, 0, (LPARAM)&cbexItem);
+}
+
+static LONG setItem(HWND cbex, int idx, const char *text) {
+ COMBOBOXEXITEMA cbexItem;
+ memset(&cbexItem, 0x00, sizeof(cbexItem));
+ cbexItem.mask = CBEIF_TEXT;
+ cbexItem.iItem = idx;
+ cbexItem.pszText = (char*)text;
+ cbexItem.cchTextMax = 0;
+ return SendMessageA(cbex, CBEM_SETITEMA, 0, (LPARAM)&cbexItem);
+}
+
+static LONG delItem(HWND cbex, int idx) {
+ return SendMessageA(cbex, CBEM_DELETEITEM, idx, 0);
+}
+
+static LONG getItem(HWND cbex, int idx, COMBOBOXEXITEMA *cbItem) {
+ memset(cbItem, 0x00, sizeof(COMBOBOXEXITEMA));
+ cbItem->mask = CBEIF_TEXT;
+ cbItem->pszText = textBuffer;
+ cbItem->iItem = idx;
+ cbItem->cchTextMax = 100;
+ return SendMessageA(cbex, CBEM_GETITEMA, 0, (LPARAM)cbItem);
+}
+
+static LRESULT WINAPI editbox_subclass_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;
+
+ msg.message = message;
+ msg.flags = sent|wparam|lparam;
+ if (defwndproc_counter) msg.flags |= defwinproc;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ msg.id = EDITBOX_ID;
+
+ if (message != WM_PAINT &&
+ message != WM_ERASEBKGND &&
+ message != WM_NCPAINT &&
+ message != WM_NCHITTEST &&
+ message != WM_GETTEXT &&
+ message != WM_GETICON &&
+ message != WM_DEVICECHANGE)
+ {
+ add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
+ }
+
+ defwndproc_counter++;
+ ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
+ defwndproc_counter--;
+ return ret;
+}
+
+static HWND subclass_editbox(HWND hwndComboEx)
+{
+ WNDPROC oldproc;
+ HWND hwnd;
+
+ hwnd = (HWND)SendMessageA(hwndComboEx, CBEM_GETEDITCONTROL, 0, 0);
+ oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
+ (LONG_PTR)editbox_subclass_proc);
+ SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
+
+ return hwnd;
+}
+
+static void test_comboex(void)
+{
+ HWND myHwnd = 0;
+ LONG res;
+ COMBOBOXEXITEMA cbexItem;
+ static const char *first_item = "First Item",
+ *second_item = "Second Item",
+ *third_item = "Third Item",
+ *middle_item = "Between First and Second Items",
+ *replacement_item = "Between First and Second Items",
+ *out_of_range_item = "Out of Range Item";
+
+ /* Allocate space for result */
+ textBuffer = HeapAlloc(GetProcessHeap(), 0, MAX_CHARS);
+
+ /* Basic comboboxex test */
+ myHwnd = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
+
+ /* Add items onto the end of the combobox */
+ res = addItem(myHwnd, -1, first_item);
+ ok(res == 0, "Adding simple item failed (%d)\n", res);
+ res = addItem(myHwnd, -1, second_item);
+ ok(res == 1, "Adding simple item failed (%d)\n", res);
+ res = addItem(myHwnd, 2, third_item);
+ ok(res == 2, "Adding simple item failed (%d)\n", res);
+ res = addItem(myHwnd, 1, middle_item);
+ ok(res == 1, "Inserting simple item failed (%d)\n", res);
+
+ /* Add an item completely out of range */
+ res = addItem(myHwnd, 99, out_of_range_item);
+ ok(res == -1, "Adding using out of range index worked unexpectedly (%d)\n", res);
+ res = addItem(myHwnd, 5, out_of_range_item);
+ ok(res == -1, "Adding using out of range index worked unexpectedly (%d)\n", res);
+ /* Removed: Causes traps on Windows XP
+ res = addItem(myHwnd, -2, "Out Of Range Item");
+ ok(res == -1, "Adding out of range worked unexpectedly (%ld)\n", res);
+ */
+
+ /* Get an item completely out of range */
+ res = getItem(myHwnd, 99, &cbexItem);
+ ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText);
+ res = getItem(myHwnd, 4, &cbexItem);
+ ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText);
+ res = getItem(myHwnd, -2, &cbexItem);
+ ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText);
+
+ /* Get an item in range */
+ res = getItem(myHwnd, 0, &cbexItem);
+ ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
+ ok(strcmp(first_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
+
+ res = getItem(myHwnd, 1, &cbexItem);
+ ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
+ ok(strcmp(middle_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
+
+ res = getItem(myHwnd, 2, &cbexItem);
+ ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
+ ok(strcmp(second_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
+
+ res = getItem(myHwnd, 3, &cbexItem);
+ ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
+ ok(strcmp(third_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
+
+ /* Set an item completely out of range */
+ res = setItem(myHwnd, 99, replacement_item);
+ ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res);
+ res = setItem(myHwnd, 4, replacement_item);
+ ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res);
+ res = setItem(myHwnd, -2, replacement_item);
+ ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res);
+
+ /* Set an item in range */
+ res = setItem(myHwnd, 0, replacement_item);
+ ok(res != 0, "Setting first item failed (%d)\n", res);
+ res = setItem(myHwnd, 3, replacement_item);
+ ok(res != 0, "Setting last item failed (%d)\n", res);
+
+ /* Remove items completely out of range (4 items in control at this point) */
+ res = delItem(myHwnd, -1);
+ ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res);
+ res = delItem(myHwnd, 4);
+ ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res);
+
+ /* Remove items in range (4 items in control at this point) */
+ res = delItem(myHwnd, 3);
+ ok(res == 3, "Deleting using out of range index failed (%d)\n", res);
+ res = delItem(myHwnd, 0);
+ ok(res == 2, "Deleting using out of range index failed (%d)\n", res);
+ res = delItem(myHwnd, 0);
+ ok(res == 1, "Deleting using out of range index failed (%d)\n", res);
+ res = delItem(myHwnd, 0);
+ ok(res == 0, "Deleting using out of range index failed (%d)\n", res);
+
+ /* Remove from an empty box */
+ res = delItem(myHwnd, 0);
+ ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res);
+
+
+ /* Cleanup */
+ HeapFree(GetProcessHeap(), 0, textBuffer);
+ DestroyWindow(myHwnd);
+}
+
+static void test_comboex_WM_LBUTTONDOWN(void)
+{
+ HWND hComboEx, hCombo, hEdit, hList;
+ COMBOBOXINFO cbInfo;
+ UINT x, y, item_height;
+ LRESULT result;
+ UINT i;
+ int idx;
+ RECT rect;
+ WCHAR buffer[3];
+ static const UINT choices[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
+ static const WCHAR stringFormat[] = {'%','2','d','\0'};
+
+ hComboEx = CreateWindowExA(0, WC_COMBOBOXEXA, NULL,
+ WS_VISIBLE|WS_CHILD|CBS_DROPDOWN, 0, 0, 200, 150,
+ hComboExParentWnd, NULL, hMainHinst, NULL);
+
+ for (i = 0; i < sizeof(choices)/sizeof(UINT); i++){
+ COMBOBOXEXITEMW cbexItem;
+ wsprintfW(buffer, stringFormat, choices[i]);
+
+ memset(&cbexItem, 0x00, sizeof(cbexItem));
+ cbexItem.mask = CBEIF_TEXT;
+ cbexItem.iItem = i;
+ cbexItem.pszText = buffer;
+ cbexItem.cchTextMax = 0;
+ ok(SendMessageW(hComboEx, CBEM_INSERTITEMW, 0, (LPARAM)&cbexItem) >= 0,
+ "Failed to add item %d\n", i);
+ }
+
+ hCombo = (HWND)SendMessageA(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0);
+ hEdit = (HWND)SendMessageA(hComboEx, CBEM_GETEDITCONTROL, 0, 0);
+
+ get_combobox_info(hCombo, &cbInfo);
+ hList = cbInfo.hwndList;
+
+ ok(GetFocus() == hComboExParentWnd,
+ "Focus not on Main Window, instead on %p\n", GetFocus());
+
+ /* Click on the button to drop down the list */
+ x = cbInfo.rcButton.left + (cbInfo.rcButton.right-cbInfo.rcButton.left)/2;
+ y = cbInfo.rcButton.top + (cbInfo.rcButton.bottom-cbInfo.rcButton.top)/2;
+ result = SendMessageA(hCombo, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y));
+ ok(result, "WM_LBUTTONDOWN was not processed. LastError=%d\n",
+ GetLastError());
+ ok(GetFocus() == hCombo ||
+ broken(GetFocus() != hCombo), /* win98 */
+ "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
+ GetFocus());
+ ok(SendMessageA(hComboEx, CB_GETDROPPEDSTATE, 0, 0),
+ "The dropdown list should have appeared after clicking the button.\n");
+ idx = SendMessageA(hCombo, CB_GETTOPINDEX, 0, 0);
+ ok(idx == 0, "For TopIndex expected %d, got %d\n", 0, idx);
+
+ result = SendMessageA(hCombo, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
+ ok(result, "WM_LBUTTONUP was not processed. LastError=%d\n",
+ GetLastError());
+ ok(GetFocus() == hCombo ||
+ broken(GetFocus() != hCombo), /* win98 */
+ "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
+ GetFocus());
+
+ /* Click on the 5th item in the list */
+ item_height = SendMessageA(hCombo, CB_GETITEMHEIGHT, 0, 0);
+ ok(GetClientRect(hList, &rect), "Failed to get list's client rect.\n");
+ x = rect.left + (rect.right-rect.left)/2;
+ y = item_height/2 + item_height*4;
+ result = SendMessageA(hList, WM_MOUSEMOVE, 0, MAKELPARAM(x, y));
+ ok(!result, "WM_MOUSEMOVE was not processed. LastError=%d\n",
+ GetLastError());
+ ok(GetFocus() == hCombo ||
+ broken(GetFocus() != hCombo), /* win98 */
+ "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
+ GetFocus());
+
+ result = SendMessageA(hList, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y));
+ ok(!result, "WM_LBUTTONDOWN was not processed. LastError=%d\n",
+ GetLastError());
+ ok(GetFocus() == hCombo ||
+ broken(GetFocus() != hCombo), /* win98 */
+ "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
+ GetFocus());
+ ok(SendMessageA(hComboEx, CB_GETDROPPEDSTATE, 0, 0),
+ "The dropdown list should still be visible.\n");
+
+ result = SendMessageA(hList, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
+ ok(!result, "WM_LBUTTONUP was not processed. LastError=%d\n",
+ GetLastError());
+ todo_wine ok(GetFocus() == hEdit ||
+ broken(GetFocus() == hCombo), /* win98 */
+ "Focus not on ComboBoxEx's Edit Control, instead on %p\n",
+ GetFocus());
+
+ result = SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0);
+ ok(!result ||
+ broken(result != 0), /* win98 */
+ "The dropdown list should have been rolled up.\n");
+ idx = SendMessageA(hComboEx, CB_GETCURSEL, 0, 0);
+ ok(idx == 4 ||
+ broken(idx == -1), /* win98 */
+ "Current Selection: expected %d, got %d\n", 4, idx);
+ ok(received_end_edit, "Expected to receive a CBEN_ENDEDIT message\n");
+
+ SetFocus( hComboExParentWnd );
+ ok( GetFocus() == hComboExParentWnd, "got %p\n", GetFocus() );
+ SetFocus( hComboEx );
+ ok( GetFocus() == hEdit, "got %p\n", GetFocus() );
+
+ DestroyWindow(hComboEx);
+}
+
+static void test_comboex_CB_GETLBTEXT(void)
+{
+ HWND hCombo;
+ CHAR buff[1];
+ COMBOBOXEXITEMA item;
+ LRESULT ret;
+
+ hCombo = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
+
+ /* set text to null */
+ addItem(hCombo, 0, NULL);
+
+ buff[0] = 'a';
+ item.mask = CBEIF_TEXT;
+ item.iItem = 0;
+ item.pszText = buff;
+ item.cchTextMax = 1;
+ ret = SendMessageA(hCombo, CBEM_GETITEMA, 0, (LPARAM)&item);
+ ok(ret != 0, "CBEM_GETITEM failed\n");
+ ok(buff[0] == 0, "\n");
+
+ ret = SendMessageA(hCombo, CB_GETLBTEXTLEN, 0, 0);
+ ok(ret == 0, "Expected zero length\n");
+
+ ret = SendMessageA(hCombo, CB_GETLBTEXTLEN, 0, 0);
+ ok(ret == 0, "Expected zero length\n");
+
+ buff[0] = 'a';
+ ret = SendMessageA(hCombo, CB_GETLBTEXT, 0, (LPARAM)buff);
+ ok(ret == 0, "Expected zero length\n");
+ ok(buff[0] == 0, "Expected null terminator as a string, got %s\n", buff);
+
+ DestroyWindow(hCombo);
+}
+
+static void test_comboex_WM_WINDOWPOSCHANGING(void)
+{
+ HWND hCombo;
+ WINDOWPOS wp;
+ RECT rect;
+ int combo_height;
+ int ret;
+
+ hCombo = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
+ ok(hCombo != NULL, "createComboEx failed\n");
+ ret = GetWindowRect(hCombo, &rect);
+ ok(ret, "GetWindowRect failed\n");
+ combo_height = rect.bottom - rect.top;
+ ok(combo_height > 0, "wrong combo height\n");
+
+ /* Test height > combo_height */
+ wp.x = rect.left;
+ wp.y = rect.top;
+ wp.cx = (rect.right - rect.left);
+ wp.cy = combo_height * 2;
+ wp.flags = 0;
+ wp.hwnd = hCombo;
+ wp.hwndInsertAfter = NULL;
+
+ ret = SendMessageA(hCombo, WM_WINDOWPOSCHANGING, 0, (LPARAM)&wp);
+ ok(ret == 0, "expected 0, got %x\n", ret);
+ ok(wp.cy == combo_height,
+ "Expected height %d, got %d\n", combo_height, wp.cy);
+
+ /* Test height < combo_height */
+ wp.x = rect.left;
+ wp.y = rect.top;
+ wp.cx = (rect.right - rect.left);
+ wp.cy = combo_height / 2;
+ wp.flags = 0;
+ wp.hwnd = hCombo;
+ wp.hwndInsertAfter = NULL;
+
+ ret = SendMessageA(hCombo, WM_WINDOWPOSCHANGING, 0, (LPARAM)&wp);
+ ok(ret == 0, "expected 0, got %x\n", ret);
+ ok(wp.cy == combo_height,
+ "Expected height %d, got %d\n", combo_height, wp.cy);
+
+ ret = DestroyWindow(hCombo);
+ ok(ret, "DestroyWindow failed\n");
+}
+
+static LRESULT ComboExTestOnNotify(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ NMHDR *hdr = (NMHDR*)lParam;
+ switch(hdr->code){
+ case CBEN_ENDEDITA:
+ {
+ NMCBEENDEDITA *edit_info = (NMCBEENDEDITA*)hdr;
+ if(edit_info->iWhy==CBENF_DROPDOWN){
+ received_end_edit = TRUE;
+ }
+ break;
+ }
+ case CBEN_ENDEDITW:
+ {
+ NMCBEENDEDITW *edit_info = (NMCBEENDEDITW*)hdr;
+ if(edit_info->iWhy==CBENF_DROPDOWN){
+ received_end_edit = TRUE;
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ case WM_NOTIFY:
+ return ComboExTestOnNotify(hWnd,msg,wParam,lParam);
+ default:
+ return DefWindowProcA(hWnd, msg, wParam, lParam);
+ }
+
+ return 0L;
+}
+
+static BOOL init(void)
+{
+ HMODULE hComctl32;
+ BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
+ WNDCLASSA wc;
+ INITCOMMONCONTROLSEX iccex;
+
+ hComctl32 = GetModuleHandleA("comctl32.dll");
+ pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
+ if (!pInitCommonControlsEx)
+ {
+ win_skip("InitCommonControlsEx() is missing. Skipping the tests\n");
+ return FALSE;
+ }
+ iccex.dwSize = sizeof(iccex);
+ iccex.dwICC = ICC_USEREX_CLASSES;
+ pInitCommonControlsEx(&iccex);
+
+ pSetWindowSubclass = (void*)GetProcAddress(hComctl32, (LPSTR)410);
+
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandleA(NULL);
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
+ wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = ComboExTestClass;
+ wc.lpfnWndProc = ComboExTestWndProc;
+ RegisterClassA(&wc);
+
+ hMainWnd = CreateWindowA("static", "Test", WS_OVERLAPPEDWINDOW, 10, 10, 300, 300, NULL, NULL, NULL, 0);
+ ShowWindow(hMainWnd, SW_SHOW);
+
+ hComboExParentWnd = CreateWindowExA(0, ComboExTestClass, "ComboEx test", WS_OVERLAPPEDWINDOW|WS_VISIBLE,
+ CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
+ ok(hComboExParentWnd != NULL, "failed to create parent window\n");
+
+ hMainHinst = GetModuleHandleA(NULL);
+
+ return hComboExParentWnd != NULL;
+}
+
+static void cleanup(void)
+{
+ MSG msg;
+
+ PostMessageA(hComboExParentWnd, WM_CLOSE, 0, 0);
+ while (GetMessageA(&msg,0,0,0)) {
+ TranslateMessage(&msg);
+ DispatchMessageA(&msg);
+ }
+
+ DestroyWindow(hComboExParentWnd);
+ UnregisterClassA(ComboExTestClass, GetModuleHandleA(NULL));
+
+ DestroyWindow(hMainWnd);
+}
+
+static void test_comboex_subclass(void)
+{
+ HWND hComboEx, hCombo, hEdit;
+
+ hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
+
+ hCombo = (HWND)SendMessageA(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0);
+ ok(hCombo != NULL, "Failed to get internal combo\n");
+ hEdit = (HWND)SendMessageA(hComboEx, CBEM_GETEDITCONTROL, 0, 0);
+ ok(hEdit != NULL, "Failed to get internal edit\n");
+
+ if (pSetWindowSubclass)
+ {
+ ok(GetPropA(hCombo, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n");
+ ok(GetPropA(hEdit, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n");
+ }
+
+ DestroyWindow(hComboEx);
+}
+
+static const struct message test_setitem_edit_seq[] = {
+ { WM_SETTEXT, sent|id, 0, 0, EDITBOX_ID },
+ { EM_SETSEL, sent|id|wparam|lparam, 0, 0, EDITBOX_ID },
+ { EM_SETSEL, sent|id|wparam|lparam, 0, -1, EDITBOX_ID },
+ { 0 }
+};
+
+static void test_comboex_get_set_item(void)
+{
+ char textA[] = "test";
+ HWND hComboEx;
+ COMBOBOXEXITEMA item;
+ BOOL ret;
+
+ hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
+
+ subclass_editbox(hComboEx);
+
+ flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+ memset(&item, 0, sizeof(item));
+ item.mask = CBEIF_TEXT;
+ item.pszText = textA;
+ item.iItem = -1;
+ ret = SendMessageA(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item);
+ expect(TRUE, ret);
+
+ ok_sequence(sequences, EDITBOX_SEQ_INDEX, test_setitem_edit_seq, "set item data for edit", FALSE);
+
+ /* get/set lParam */
+ item.mask = CBEIF_LPARAM;
+ item.iItem = -1;
+ item.lParam = 0xdeadbeef;
+ ret = SendMessageA(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item);
+ expect(TRUE, ret);
+ ok(item.lParam == 0, "Expected zero, got %lx\n", item.lParam);
+
+ item.lParam = 0x1abe11ed;
+ ret = SendMessageA(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item);
+ expect(TRUE, ret);
+
+ item.lParam = 0;
+ ret = SendMessageA(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item);
+ expect(TRUE, ret);
+ ok(item.lParam == 0x1abe11ed, "Expected 0x1abe11ed, got %lx\n", item.lParam);
+
+ DestroyWindow(hComboEx);
+}
+
+static HWND create_combobox(DWORD style)
+{
+ return CreateWindowA("ComboBox", "Combo", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)COMBO_ID, NULL, 0);
+}
+
+static int font_height(HFONT hFont)
+{
+ TEXTMETRICA tm;
+ HFONT hFontOld;
+ HDC hDC;
+
+ hDC = CreateCompatibleDC(NULL);
+ hFontOld = SelectObject(hDC, hFont);
+ GetTextMetricsA(hDC, &tm);
+ SelectObject(hDC, hFontOld);
+ DeleteDC(hDC);
+
+ return tm.tmHeight;
+}
+
+static void test_combo_setitemheight(DWORD style)
+{
+ HWND hCombo = create_combobox(style);
+ RECT r;
+ int i;
+
+ GetClientRect(hCombo, &r);
+ expect_rect(r, 0, 0, 100, font_height(GetStockObject(SYSTEM_FONT)) + 8);
+ SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
+ MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
+ todo_wine expect_rect(r, 5, 5, 105, 105);
+
+ for (i = 1; i < 30; i++)
+ {
+ SendMessageA(hCombo, CB_SETITEMHEIGHT, -1, i);
+ GetClientRect(hCombo, &r);
+ ok((r.bottom - r.top) == (i + 6), "Unexpected client rect height.\n");
+ }
+
+ DestroyWindow(hCombo);
+}
+
+static void test_combo_setfont(DWORD style)
+{
+ HFONT hFont1, hFont2;
+ HWND hCombo;
+ RECT r;
+ int i;
+
+ hCombo = create_combobox(style);
+ hFont1 = CreateFontA(10, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett");
+ hFont2 = CreateFontA(8, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett");
+
+ GetClientRect(hCombo, &r);
+ expect_rect(r, 0, 0, 100, font_height(GetStockObject(SYSTEM_FONT)) + 8);
+ SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
+ MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
+ todo_wine expect_rect(r, 5, 5, 105, 105);
+
+ /* The size of the dropped control is initially equal to the size
+ of the window when it was created. The size of the calculated
+ dropped area changes only by how much the selection area
+ changes, not by how much the list area changes. */
+ if (font_height(hFont1) == 10 && font_height(hFont2) == 8)
+ {
+ SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE);
+ GetClientRect(hCombo, &r);
+ expect_rect(r, 0, 0, 100, 18);
+ SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
+ MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
+ todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont1)));
+
+ SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont2, FALSE);
+ GetClientRect(hCombo, &r);
+ expect_rect(r, 0, 0, 100, 16);
+ SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
+ MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
+ todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont2)));
+
+ SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE);
+ GetClientRect(hCombo, &r);
+ expect_rect(r, 0, 0, 100, 18);
+ SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
+ MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
+ todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont1)));
+ }
+ else
+ {
+ ok(0, "Expected Marlett font heights 10/8, got %d/%d\n",
+ font_height(hFont1), font_height(hFont2));
+ }
+
+ for (i = 1; i < 30; i++)
+ {
+ HFONT hFont = CreateFontA(i, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett");
+ int height = font_height(hFont);
+
+ SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont, FALSE);
+ GetClientRect(hCombo, &r);
+ ok((r.bottom - r.top) == (height + 8), "Unexpected client rect height.\n");
+ SendMessageA(hCombo, WM_SETFONT, 0, FALSE);
+ DeleteObject(hFont);
+ }
+
+ DestroyWindow(hCombo);
+ DeleteObject(hFont1);
+ DeleteObject(hFont2);
+}
+
+static LRESULT (CALLBACK *old_parent_proc)(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+static LPCSTR expected_edit_text;
+static LPCSTR expected_list_text;
+static BOOL selchange_fired;
+
+static LRESULT CALLBACK parent_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_COMMAND:
+ switch (wparam)
+ {
+ case MAKEWPARAM(COMBO_ID, CBN_SELCHANGE):
+ {
+ HWND hCombo = (HWND)lparam;
+ char list[20], edit[20];
+ int idx;
+
+ memset(list, 0, sizeof(list));
+ memset(edit, 0, sizeof(edit));
+
+ idx = SendMessageA(hCombo, CB_GETCURSEL, 0, 0);
+ SendMessageA(hCombo, CB_GETLBTEXT, idx, (LPARAM)list);
+ SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
+
+ ok(!strcmp(edit, expected_edit_text), "edit: got %s, expected %s\n",
+ edit, expected_edit_text);
+ ok(!strcmp(list, expected_list_text), "list: got %s, expected %s\n",
+ list, expected_list_text);
+
+ selchange_fired = TRUE;
+ }
+ break;
+ }
+ break;
+ }
+
+ return CallWindowProcA(old_parent_proc, hwnd, msg, wparam, lparam);
+}
+
+static void test_selection(DWORD style, const char * const text[], const int *edit, const int *list)
+{
+ HWND hCombo;
+ INT idx;
+
+ hCombo = create_combobox(style);
+
+ SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)text[0]);
+ SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)text[1]);
+ SendMessageA(hCombo, CB_SETCURSEL, -1, 0);
+
+ old_parent_proc = (void *)SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)parent_wnd_proc);
+
+ idx = SendMessageA(hCombo, CB_GETCURSEL, 0, 0);
+ ok(idx == -1, "expected selection -1, got %d\n", idx);
+
+ /* keyboard navigation */
+
+ expected_list_text = text[list[0]];
+ expected_edit_text = text[edit[0]];
+ selchange_fired = FALSE;
+ SendMessageA(hCombo, WM_KEYDOWN, VK_DOWN, 0);
+ ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
+
+ expected_list_text = text[list[1]];
+ expected_edit_text = text[edit[1]];
+ selchange_fired = FALSE;
+ SendMessageA(hCombo, WM_KEYDOWN, VK_DOWN, 0);
+ ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
+
+ expected_list_text = text[list[2]];
+ expected_edit_text = text[edit[2]];
+ selchange_fired = FALSE;
+ SendMessageA(hCombo, WM_KEYDOWN, VK_UP, 0);
+ ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
+
+ /* programmatic navigation */
+
+ expected_list_text = text[list[3]];
+ expected_edit_text = text[edit[3]];
+ selchange_fired = FALSE;
+ SendMessageA(hCombo, CB_SETCURSEL, list[3], 0);
+ ok(!selchange_fired, "CBN_SELCHANGE sent!\n");
+
+ expected_list_text = text[list[4]];
+ expected_edit_text = text[edit[4]];
+ selchange_fired = FALSE;
+ SendMessageA(hCombo, CB_SETCURSEL, list[4], 0);
+ ok(!selchange_fired, "CBN_SELCHANGE sent!\n");
+
+ SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)old_parent_proc);
+ DestroyWindow(hCombo);
+}
+
+static void test_combo_CBN_SELCHANGE(void)
+{
+ static const char * const text[] = { "alpha", "beta", "" };
+ static const int sel_1[] = { 2, 0, 1, 0, 1 };
+ static const int sel_2[] = { 0, 1, 0, 0, 1 };
+
+ test_selection(CBS_SIMPLE, text, sel_1, sel_2);
+ test_selection(CBS_DROPDOWN, text, sel_1, sel_2);
+ test_selection(CBS_DROPDOWNLIST, text, sel_2, sel_2);
+}
+
+static void test_combo_changesize(DWORD style)
+{
+ INT ddheight, clheight, ddwidth, clwidth;
+ HWND hCombo;
+ RECT rc;
+
+ hCombo = create_combobox(style);
+
+ /* get initial measurements */
+ GetClientRect( hCombo, &rc);
+ clheight = rc.bottom - rc.top;
+ clwidth = rc.right - rc.left;
+ SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc);
+ ddheight = rc.bottom - rc.top;
+ ddwidth = rc.right - rc.left;
+ /* use MoveWindow to move & resize the combo */
+ /* first make it slightly smaller */
+ MoveWindow( hCombo, 10, 10, clwidth - 2, clheight - 2, TRUE);
+ GetClientRect( hCombo, &rc);
+ ok( rc.right - rc.left == clwidth - 2, "clientrect width is %d vs %d\n",
+ rc.right - rc.left, clwidth - 2);
+ ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n",
+ rc.bottom - rc.top, clheight);
+ SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc);
+ ok( rc.right - rc.left == clwidth - 2, "drop-down rect width is %d vs %d\n",
+ rc.right - rc.left, clwidth - 2);
+ ok( rc.bottom - rc.top == ddheight, "drop-down rect height is %d vs %d\n",
+ rc.bottom - rc.top, ddheight);
+ ok( rc.right - rc.left == ddwidth -2, "drop-down rect width is %d vs %d\n",
+ rc.right - rc.left, ddwidth - 2);
+ /* new cx, cy is slightly bigger than the initial values */
+ MoveWindow( hCombo, 10, 10, clwidth + 2, clheight + 2, TRUE);
+ GetClientRect( hCombo, &rc);
+ ok( rc.right - rc.left == clwidth + 2, "clientrect width is %d vs %d\n",
+ rc.right - rc.left, clwidth + 2);
+ ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n",
+ rc.bottom - rc.top, clheight);
+ SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc);
+ ok( rc.right - rc.left == clwidth + 2, "drop-down rect width is %d vs %d\n",
+ rc.right - rc.left, clwidth + 2);
+ todo_wine {
+ ok( rc.bottom - rc.top == clheight + 2, "drop-down rect height is %d vs %d\n",
+ rc.bottom - rc.top, clheight + 2);
+ }
+
+ ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, -1, 0);
+ ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
+ ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
+ ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
+
+ ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 0, 0);
+ ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
+ ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
+ ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
+
+ ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, clwidth - 1, 0);
+ ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
+ ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
+ ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
+
+ ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, clwidth << 1, 0);
+ ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
+ ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
+ ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
+
+ ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 0, 0);
+ ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
+ ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
+ ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
+
+ ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 1, 0);
+ ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
+ ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
+ ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
+
+ DestroyWindow(hCombo);
+}
+
+static void test_combo_editselection(void)
+{
+ COMBOBOXINFO cbInfo;
+ INT start, end;
+ char edit[20];
+ HWND hCombo;
+ HWND hEdit;
+ DWORD len;
+
+ /* Build a combo */
+ hCombo = create_combobox(CBS_SIMPLE);
+
+ get_combobox_info(hCombo, &cbInfo);
+ hEdit = cbInfo.hwndItem;
+
+ /* Initially combo selection is empty*/
+ len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
+ ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
+ ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len));
+
+ /* Set some text, and press a key to replace it */
+ edit[0] = 0x00;
+ SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)"Jason1");
+ SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
+ ok(strcmp(edit, "Jason1")==0, "Unexpected text retrieved %s\n", edit);
+
+ /* Now what is the selection - still empty */
+ SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end);
+ ok(start==0, "Unexpected start position for selection %d\n", start);
+ ok(end==0, "Unexpected end position for selection %d\n", end);
+ len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
+ ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
+ ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len));
+
+ /* Give it focus, and it gets selected */
+ SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
+ SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end);
+ ok(start==0, "Unexpected start position for selection %d\n", start);
+ ok(end==6, "Unexpected end position for selection %d\n", end);
+ len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
+ ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
+ ok(HIWORD(len)==6, "Unexpected end position for selection %d\n", HIWORD(len));
+
+ /* Now emulate a key press */
+ edit[0] = 0x00;
+ SendMessageA(hCombo, WM_CHAR, 'A', 0x1c0001);
+ SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
+ ok(strcmp(edit, "A")==0, "Unexpected text retrieved %s\n", edit);
+
+ len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
+ ok(LOWORD(len)==1, "Unexpected start position for selection %d\n", LOWORD(len));
+ ok(HIWORD(len)==1, "Unexpected end position for selection %d\n", HIWORD(len));
+
+ /* Now what happens when it gets more focus a second time - it doesn't reselect */
+ SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
+ len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
+ ok(LOWORD(len)==1, "Unexpected start position for selection %d\n", LOWORD(len));
+ ok(HIWORD(len)==1, "Unexpected end position for selection %d\n", HIWORD(len));
+ DestroyWindow(hCombo);
+
+ /* Start again - Build a combo */
+ hCombo = create_combobox(CBS_SIMPLE);
+ get_combobox_info(hCombo, &cbInfo);
+ hEdit = cbInfo.hwndItem;
+
+ /* Set some text and give focus so it gets selected */
+ edit[0] = 0x00;
+ SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)"Jason2");
+ SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
+ ok(strcmp(edit, "Jason2")==0, "Unexpected text retrieved %s\n", edit);
+
+ SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
+
+ /* Now what is the selection */
+ SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end);
+ ok(start==0, "Unexpected start position for selection %d\n", start);
+ ok(end==6, "Unexpected end position for selection %d\n", end);
+ len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
+ ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
+ ok(HIWORD(len)==6, "Unexpected end position for selection %d\n", HIWORD(len));
+
+ /* Now change the selection to the apparently invalid start -1, end -1 and
+ show it means no selection (ie start -1) but cursor at end */
+ SendMessageA(hCombo, CB_SETEDITSEL, 0, -1);
+ edit[0] = 0x00;
+ SendMessageA(hCombo, WM_CHAR, 'A', 0x1c0001);
+ SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
+ ok(strcmp(edit, "Jason2A")==0, "Unexpected text retrieved %s\n", edit);
+ DestroyWindow(hCombo);
+}
+
+static WNDPROC edit_window_proc;
+static long setsel_start = 1, setsel_end = 1;
+static HWND hCBN_SetFocus, hCBN_KillFocus;
+
+static LRESULT CALLBACK combobox_subclass_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg == EM_SETSEL)
+ {
+ setsel_start = wParam;
+ setsel_end = lParam;
+ }
+ return CallWindowProcA(edit_window_proc, hwnd, msg, wParam, lParam);
+}
+
+static LRESULT CALLBACK test_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_COMMAND:
+ switch (HIWORD(wParam))
+ {
+ case CBN_SETFOCUS:
+ hCBN_SetFocus = (HWND)lParam;
+ break;
+ case CBN_KILLFOCUS:
+ hCBN_KillFocus = (HWND)lParam;
+ break;
+ }
+ break;
+ case WM_NEXTDLGCTL:
+ SetFocus((HWND)wParam);
+ break;
+ }
+ return CallWindowProcA(old_parent_proc, hwnd, msg, wParam, lParam);
+}
+
+static void test_combo_editselection_focus(DWORD style)
+{
+ static const char wine_test[] = "Wine Test";
+ HWND hCombo, hEdit, hButton;
+ char buffer[16] = {0};
+ COMBOBOXINFO cbInfo;
+ DWORD len;
+
+ hCombo = create_combobox(style);
+ get_combobox_info(hCombo, &cbInfo);
+ hEdit = cbInfo.hwndItem;
+
+ hButton = CreateWindowA("Button", "OK", WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON,
+ 5, 50, 100, 20, hMainWnd, NULL,
+ (HINSTANCE)GetWindowLongPtrA(hMainWnd, GWLP_HINSTANCE), NULL);
+
+ old_parent_proc = (WNDPROC)SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)test_window_proc);
+ edit_window_proc = (WNDPROC)SetWindowLongPtrA(hEdit, GWLP_WNDPROC, (ULONG_PTR)combobox_subclass_proc);
+
+ SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
+ ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start);
+ todo_wine ok(setsel_end == INT_MAX, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end);
+ ok(hCBN_SetFocus == hCombo, "Wrong handle set by CBN_SETFOCUS; got %p\n", hCBN_SetFocus);
+ ok(GetFocus() == hEdit, "hEdit should have keyboard focus\n");
+
+ SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hButton, TRUE);
+ ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start);
+ todo_wine ok(setsel_end == 0, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end);
+ ok(hCBN_KillFocus == hCombo, "Wrong handle set by CBN_KILLFOCUS; got %p\n", hCBN_KillFocus);
+ ok(GetFocus() == hButton, "hButton should have keyboard focus\n");
+
+ SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)wine_test);
+ SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hCombo, TRUE);
+ ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start);
+ todo_wine ok(setsel_end == INT_MAX, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end);
+ ok(hCBN_SetFocus == hCombo, "Wrong handle set by CBN_SETFOCUS; got %p\n", hCBN_SetFocus);
+ ok(GetFocus() == hEdit, "hEdit should have keyboard focus\n");
+ SendMessageA(hCombo, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
+ ok(!strcmp(buffer, wine_test), "Unexpected text in edit control; got '%s'\n", buffer);
+
+ SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hButton, TRUE);
+ ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start);
+ todo_wine ok(setsel_end == 0, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end);
+ ok(hCBN_KillFocus == hCombo, "Wrong handle set by CBN_KILLFOCUS; got %p\n", hCBN_KillFocus);
+ ok(GetFocus() == hButton, "hButton should have keyboard focus\n");
+ len = SendMessageA(hCombo, CB_GETEDITSEL, 0, 0);
+ ok(len == 0, "Unexpected text selection; start: %u, end: %u\n", LOWORD(len), HIWORD(len));
+
+ SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)old_parent_proc);
+ DestroyWindow(hButton);
+ DestroyWindow(hCombo);
+}
+
+static void test_combo_listbox_styles(DWORD cb_style)
+{
+ DWORD style, exstyle, expect_style, expect_exstyle;
+ COMBOBOXINFO info;
+ HWND combo;
+
+ expect_style = WS_CHILD|WS_CLIPSIBLINGS|LBS_COMBOBOX|LBS_HASSTRINGS|LBS_NOTIFY;
+ if (cb_style == CBS_SIMPLE)
+ {
+ expect_style |= WS_VISIBLE;
+ expect_exstyle = WS_EX_CLIENTEDGE;
+ }
+ else
+ {
+ expect_style |= WS_BORDER;
+ expect_exstyle = WS_EX_TOOLWINDOW;
+ }
+
+ combo = create_combobox(cb_style);
+ get_combobox_info(combo, &info);
+
+ style = GetWindowLongW( info.hwndList, GWL_STYLE );
+ exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE );
+ ok(style == expect_style, "%08x: got %08x\n", cb_style, style);
+ ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle);
+
+ if (cb_style != CBS_SIMPLE)
+ expect_exstyle |= WS_EX_TOPMOST;
+
+ SendMessageW(combo, CB_SHOWDROPDOWN, TRUE, 0 );
+ style = GetWindowLongW( info.hwndList, GWL_STYLE );
+ exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE );
+ ok(style == (expect_style | WS_VISIBLE), "%08x: got %08x\n", cb_style, style);
+ ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle);
+
+ SendMessageW(combo, CB_SHOWDROPDOWN, FALSE, 0 );
+ style = GetWindowLongW( info.hwndList, GWL_STYLE );
+ exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE );
+ ok(style == expect_style, "%08x: got %08x\n", cb_style, style);
+ ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle);
+
+ DestroyWindow(combo);
+}
+
+static void test_combo_WS_VSCROLL(void)
+{
+ HWND hCombo, hList;
+ COMBOBOXINFO info;
+ DWORD style;
+ int i;
+
+ hCombo = create_combobox(CBS_DROPDOWNLIST);
+
+ get_combobox_info(hCombo, &info);
+ hList = info.hwndList;
+
+ for (i = 0; i < 3; i++)
+ {
+ char buffer[2];
+ sprintf(buffer, "%d", i);
+ SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)buffer);
+ }
+
+ style = GetWindowLongA(info.hwndList, GWL_STYLE);
+ SetWindowLongA(hList, GWL_STYLE, style | WS_VSCROLL);
+
+ SendMessageA(hCombo, CB_SHOWDROPDOWN, TRUE, 0);
+ SendMessageA(hCombo, CB_SHOWDROPDOWN, FALSE, 0);
+
+ style = GetWindowLongA(hList, GWL_STYLE);
+ ok((style & WS_VSCROLL) != 0, "Style does not include WS_VSCROLL\n");
+
+ DestroyWindow(hCombo);
+}
+
+START_TEST(combo)
+{
+ ULONG_PTR ctx_cookie;
+ HANDLE hCtx;
+
+ if (!init())
+ return;
+
+ init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
+
+ /* ComboBoxEx32 tests. */
+ test_comboex();
+ test_comboex_WM_LBUTTONDOWN();
+ test_comboex_CB_GETLBTEXT();
+ test_comboex_WM_WINDOWPOSCHANGING();
+ test_comboex_subclass();
+ test_comboex_get_set_item();
+
+ if (!load_v6_module(&ctx_cookie, &hCtx))
+ {
+ cleanup();
+ return;
+ }
+
+ /* ComboBox control tests. */
+ test_combo_WS_VSCROLL();
+ test_combo_setfont(CBS_DROPDOWN);
+ test_combo_setfont(CBS_DROPDOWNLIST);
+ test_combo_setitemheight(CBS_DROPDOWN);
+ test_combo_setitemheight(CBS_DROPDOWNLIST);
+ test_combo_CBN_SELCHANGE();
+ test_combo_changesize(CBS_DROPDOWN);
+ test_combo_changesize(CBS_DROPDOWNLIST);
+ test_combo_editselection();
+ test_combo_editselection_focus(CBS_SIMPLE);
+ test_combo_editselection_focus(CBS_DROPDOWN);
+ test_combo_listbox_styles(CBS_SIMPLE);
+ test_combo_listbox_styles(CBS_DROPDOWN);
+ test_combo_listbox_styles(CBS_DROPDOWNLIST);
+
+ cleanup();
+ unload_v6_module(ctx_cookie, hCtx);
+}
+++ /dev/null
-/* Unit test suite for comboex control.
- *
- * Copyright 2005 Jason Edmeades
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "precomp.h"
-
-#define EDITBOX_SEQ_INDEX 0
-#define NUM_MSG_SEQUENCES 1
-
-#define EDITBOX_ID 0
-
-#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
-
-static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
-
-static HWND hComboExParentWnd;
-static HINSTANCE hMainHinst;
-static const char ComboExTestClass[] = "ComboExTestClass";
-
-static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
-
-#define MAX_CHARS 100
-static char *textBuffer = NULL;
-
-static BOOL received_end_edit = FALSE;
-
-static HWND createComboEx(DWORD style) {
- return CreateWindowExA(0, WC_COMBOBOXEXA, NULL, style, 0, 0, 300, 300,
- hComboExParentWnd, NULL, hMainHinst, NULL);
-}
-
-static LONG addItem(HWND cbex, int idx, const char *text) {
- COMBOBOXEXITEMA cbexItem;
- memset(&cbexItem, 0x00, sizeof(cbexItem));
- cbexItem.mask = CBEIF_TEXT;
- cbexItem.iItem = idx;
- cbexItem.pszText = (char*)text;
- cbexItem.cchTextMax = 0;
- return SendMessageA(cbex, CBEM_INSERTITEMA, 0, (LPARAM)&cbexItem);
-}
-
-static LONG setItem(HWND cbex, int idx, const char *text) {
- COMBOBOXEXITEMA cbexItem;
- memset(&cbexItem, 0x00, sizeof(cbexItem));
- cbexItem.mask = CBEIF_TEXT;
- cbexItem.iItem = idx;
- cbexItem.pszText = (char*)text;
- cbexItem.cchTextMax = 0;
- return SendMessageA(cbex, CBEM_SETITEMA, 0, (LPARAM)&cbexItem);
-}
-
-static LONG delItem(HWND cbex, int idx) {
- return SendMessageA(cbex, CBEM_DELETEITEM, idx, 0);
-}
-
-static LONG getItem(HWND cbex, int idx, COMBOBOXEXITEMA *cbItem) {
- memset(cbItem, 0x00, sizeof(COMBOBOXEXITEMA));
- cbItem->mask = CBEIF_TEXT;
- cbItem->pszText = textBuffer;
- cbItem->iItem = idx;
- cbItem->cchTextMax = 100;
- return SendMessageA(cbex, CBEM_GETITEMA, 0, (LPARAM)cbItem);
-}
-
-static LRESULT WINAPI editbox_subclass_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;
-
- msg.message = message;
- msg.flags = sent|wparam|lparam;
- if (defwndproc_counter) msg.flags |= defwinproc;
- msg.wParam = wParam;
- msg.lParam = lParam;
- msg.id = EDITBOX_ID;
-
- if (message != WM_PAINT &&
- message != WM_ERASEBKGND &&
- message != WM_NCPAINT &&
- message != WM_NCHITTEST &&
- message != WM_GETTEXT &&
- message != WM_GETICON &&
- message != WM_DEVICECHANGE)
- {
- add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
- }
-
- defwndproc_counter++;
- ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
- defwndproc_counter--;
- return ret;
-}
-
-static HWND subclass_editbox(HWND hwndComboEx)
-{
- WNDPROC oldproc;
- HWND hwnd;
-
- hwnd = (HWND)SendMessageA(hwndComboEx, CBEM_GETEDITCONTROL, 0, 0);
- oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
- (LONG_PTR)editbox_subclass_proc);
- SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
-
- return hwnd;
-}
-
-static void test_comboboxex(void) {
- HWND myHwnd = 0;
- LONG res;
- COMBOBOXEXITEMA cbexItem;
- static const char *first_item = "First Item",
- *second_item = "Second Item",
- *third_item = "Third Item",
- *middle_item = "Between First and Second Items",
- *replacement_item = "Between First and Second Items",
- *out_of_range_item = "Out of Range Item";
-
- /* Allocate space for result */
- textBuffer = HeapAlloc(GetProcessHeap(), 0, MAX_CHARS);
-
- /* Basic comboboxex test */
- myHwnd = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
-
- /* Add items onto the end of the combobox */
- res = addItem(myHwnd, -1, first_item);
- ok(res == 0, "Adding simple item failed (%d)\n", res);
- res = addItem(myHwnd, -1, second_item);
- ok(res == 1, "Adding simple item failed (%d)\n", res);
- res = addItem(myHwnd, 2, third_item);
- ok(res == 2, "Adding simple item failed (%d)\n", res);
- res = addItem(myHwnd, 1, middle_item);
- ok(res == 1, "Inserting simple item failed (%d)\n", res);
-
- /* Add an item completely out of range */
- res = addItem(myHwnd, 99, out_of_range_item);
- ok(res == -1, "Adding using out of range index worked unexpectedly (%d)\n", res);
- res = addItem(myHwnd, 5, out_of_range_item);
- ok(res == -1, "Adding using out of range index worked unexpectedly (%d)\n", res);
- /* Removed: Causes traps on Windows XP
- res = addItem(myHwnd, -2, "Out Of Range Item");
- ok(res == -1, "Adding out of range worked unexpectedly (%ld)\n", res);
- */
-
- /* Get an item completely out of range */
- res = getItem(myHwnd, 99, &cbexItem);
- ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText);
- res = getItem(myHwnd, 4, &cbexItem);
- ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText);
- res = getItem(myHwnd, -2, &cbexItem);
- ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText);
-
- /* Get an item in range */
- res = getItem(myHwnd, 0, &cbexItem);
- ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
- ok(strcmp(first_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
-
- res = getItem(myHwnd, 1, &cbexItem);
- ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
- ok(strcmp(middle_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
-
- res = getItem(myHwnd, 2, &cbexItem);
- ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
- ok(strcmp(second_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
-
- res = getItem(myHwnd, 3, &cbexItem);
- ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
- ok(strcmp(third_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
-
- /* Set an item completely out of range */
- res = setItem(myHwnd, 99, replacement_item);
- ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res);
- res = setItem(myHwnd, 4, replacement_item);
- ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res);
- res = setItem(myHwnd, -2, replacement_item);
- ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res);
-
- /* Set an item in range */
- res = setItem(myHwnd, 0, replacement_item);
- ok(res != 0, "Setting first item failed (%d)\n", res);
- res = setItem(myHwnd, 3, replacement_item);
- ok(res != 0, "Setting last item failed (%d)\n", res);
-
- /* Remove items completely out of range (4 items in control at this point) */
- res = delItem(myHwnd, -1);
- ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res);
- res = delItem(myHwnd, 4);
- ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res);
-
- /* Remove items in range (4 items in control at this point) */
- res = delItem(myHwnd, 3);
- ok(res == 3, "Deleting using out of range index failed (%d)\n", res);
- res = delItem(myHwnd, 0);
- ok(res == 2, "Deleting using out of range index failed (%d)\n", res);
- res = delItem(myHwnd, 0);
- ok(res == 1, "Deleting using out of range index failed (%d)\n", res);
- res = delItem(myHwnd, 0);
- ok(res == 0, "Deleting using out of range index failed (%d)\n", res);
-
- /* Remove from an empty box */
- res = delItem(myHwnd, 0);
- ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res);
-
-
- /* Cleanup */
- HeapFree(GetProcessHeap(), 0, textBuffer);
- DestroyWindow(myHwnd);
-}
-
-static void test_WM_LBUTTONDOWN(void)
-{
- HWND hComboEx, hCombo, hEdit, hList;
- COMBOBOXINFO cbInfo;
- UINT x, y, item_height;
- LRESULT result;
- UINT i;
- int idx;
- RECT rect;
- WCHAR buffer[3];
- static const UINT choices[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
- static const WCHAR stringFormat[] = {'%','2','d','\0'};
- BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO);
-
- pGetComboBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo");
- if (!pGetComboBoxInfo){
- win_skip("GetComboBoxInfo is not available\n");
- return;
- }
-
- hComboEx = CreateWindowExA(0, WC_COMBOBOXEXA, NULL,
- WS_VISIBLE|WS_CHILD|CBS_DROPDOWN, 0, 0, 200, 150,
- hComboExParentWnd, NULL, hMainHinst, NULL);
-
- for (i = 0; i < sizeof(choices)/sizeof(UINT); i++){
- COMBOBOXEXITEMW cbexItem;
- wsprintfW(buffer, stringFormat, choices[i]);
-
- memset(&cbexItem, 0x00, sizeof(cbexItem));
- cbexItem.mask = CBEIF_TEXT;
- cbexItem.iItem = i;
- cbexItem.pszText = buffer;
- cbexItem.cchTextMax = 0;
- ok(SendMessageW(hComboEx, CBEM_INSERTITEMW, 0, (LPARAM)&cbexItem) >= 0,
- "Failed to add item %d\n", i);
- }
-
- hCombo = (HWND)SendMessageA(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0);
- hEdit = (HWND)SendMessageA(hComboEx, CBEM_GETEDITCONTROL, 0, 0);
-
- cbInfo.cbSize = sizeof(COMBOBOXINFO);
- result = pGetComboBoxInfo(hCombo, &cbInfo);
- ok(result, "Failed to get combobox info structure. LastError=%d\n",
- GetLastError());
- hList = cbInfo.hwndList;
-
- ok(GetFocus() == hComboExParentWnd,
- "Focus not on Main Window, instead on %p\n", GetFocus());
-
- /* Click on the button to drop down the list */
- x = cbInfo.rcButton.left + (cbInfo.rcButton.right-cbInfo.rcButton.left)/2;
- y = cbInfo.rcButton.top + (cbInfo.rcButton.bottom-cbInfo.rcButton.top)/2;
- result = SendMessageA(hCombo, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y));
- ok(result, "WM_LBUTTONDOWN was not processed. LastError=%d\n",
- GetLastError());
- ok(GetFocus() == hCombo ||
- broken(GetFocus() != hCombo), /* win98 */
- "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
- GetFocus());
- ok(SendMessageA(hComboEx, CB_GETDROPPEDSTATE, 0, 0),
- "The dropdown list should have appeared after clicking the button.\n");
- idx = SendMessageA(hCombo, CB_GETTOPINDEX, 0, 0);
- ok(idx == 0, "For TopIndex expected %d, got %d\n", 0, idx);
-
- result = SendMessageA(hCombo, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
- ok(result, "WM_LBUTTONUP was not processed. LastError=%d\n",
- GetLastError());
- ok(GetFocus() == hCombo ||
- broken(GetFocus() != hCombo), /* win98 */
- "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
- GetFocus());
-
- /* Click on the 5th item in the list */
- item_height = SendMessageA(hCombo, CB_GETITEMHEIGHT, 0, 0);
- ok(GetClientRect(hList, &rect), "Failed to get list's client rect.\n");
- x = rect.left + (rect.right-rect.left)/2;
- y = item_height/2 + item_height*4;
- result = SendMessageA(hList, WM_MOUSEMOVE, 0, MAKELPARAM(x, y));
- ok(!result, "WM_MOUSEMOVE was not processed. LastError=%d\n",
- GetLastError());
- ok(GetFocus() == hCombo ||
- broken(GetFocus() != hCombo), /* win98 */
- "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
- GetFocus());
-
- result = SendMessageA(hList, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y));
- ok(!result, "WM_LBUTTONDOWN was not processed. LastError=%d\n",
- GetLastError());
- ok(GetFocus() == hCombo ||
- broken(GetFocus() != hCombo), /* win98 */
- "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
- GetFocus());
- ok(SendMessageA(hComboEx, CB_GETDROPPEDSTATE, 0, 0),
- "The dropdown list should still be visible.\n");
-
- result = SendMessageA(hList, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
- ok(!result, "WM_LBUTTONUP was not processed. LastError=%d\n",
- GetLastError());
- todo_wine ok(GetFocus() == hEdit ||
- broken(GetFocus() == hCombo), /* win98 */
- "Focus not on ComboBoxEx's Edit Control, instead on %p\n",
- GetFocus());
-
- result = SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0);
- ok(!result ||
- broken(result != 0), /* win98 */
- "The dropdown list should have been rolled up.\n");
- idx = SendMessageA(hComboEx, CB_GETCURSEL, 0, 0);
- ok(idx == 4 ||
- broken(idx == -1), /* win98 */
- "Current Selection: expected %d, got %d\n", 4, idx);
- ok(received_end_edit, "Expected to receive a CBEN_ENDEDIT message\n");
-
- SetFocus( hComboExParentWnd );
- ok( GetFocus() == hComboExParentWnd, "got %p\n", GetFocus() );
- SetFocus( hComboEx );
- ok( GetFocus() == hEdit, "got %p\n", GetFocus() );
-
- DestroyWindow(hComboEx);
-}
-
-static void test_CB_GETLBTEXT(void)
-{
- HWND hCombo;
- CHAR buff[1];
- COMBOBOXEXITEMA item;
- LRESULT ret;
-
- hCombo = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
-
- /* set text to null */
- addItem(hCombo, 0, NULL);
-
- buff[0] = 'a';
- item.mask = CBEIF_TEXT;
- item.iItem = 0;
- item.pszText = buff;
- item.cchTextMax = 1;
- ret = SendMessageA(hCombo, CBEM_GETITEMA, 0, (LPARAM)&item);
- ok(ret != 0, "CBEM_GETITEM failed\n");
- ok(buff[0] == 0, "\n");
-
- ret = SendMessageA(hCombo, CB_GETLBTEXTLEN, 0, 0);
- ok(ret == 0, "Expected zero length\n");
-
- ret = SendMessageA(hCombo, CB_GETLBTEXTLEN, 0, 0);
- ok(ret == 0, "Expected zero length\n");
-
- buff[0] = 'a';
- ret = SendMessageA(hCombo, CB_GETLBTEXT, 0, (LPARAM)buff);
- ok(ret == 0, "Expected zero length\n");
- ok(buff[0] == 0, "Expected null terminator as a string, got %s\n", buff);
-
- DestroyWindow(hCombo);
-}
-
-static void test_WM_WINDOWPOSCHANGING(void)
-{
- HWND hCombo;
- WINDOWPOS wp;
- RECT rect;
- int combo_height;
- int ret;
-
- hCombo = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
- ok(hCombo != NULL, "createComboEx failed\n");
- ret = GetWindowRect(hCombo, &rect);
- ok(ret, "GetWindowRect failed\n");
- combo_height = rect.bottom - rect.top;
- ok(combo_height > 0, "wrong combo height\n");
-
- /* Test height > combo_height */
- wp.x = rect.left;
- wp.y = rect.top;
- wp.cx = (rect.right - rect.left);
- wp.cy = combo_height * 2;
- wp.flags = 0;
- wp.hwnd = hCombo;
- wp.hwndInsertAfter = NULL;
-
- ret = SendMessageA(hCombo, WM_WINDOWPOSCHANGING, 0, (LPARAM)&wp);
- ok(ret == 0, "expected 0, got %x\n", ret);
- ok(wp.cy == combo_height,
- "Expected height %d, got %d\n", combo_height, wp.cy);
-
- /* Test height < combo_height */
- wp.x = rect.left;
- wp.y = rect.top;
- wp.cx = (rect.right - rect.left);
- wp.cy = combo_height / 2;
- wp.flags = 0;
- wp.hwnd = hCombo;
- wp.hwndInsertAfter = NULL;
-
- ret = SendMessageA(hCombo, WM_WINDOWPOSCHANGING, 0, (LPARAM)&wp);
- ok(ret == 0, "expected 0, got %x\n", ret);
- ok(wp.cy == combo_height,
- "Expected height %d, got %d\n", combo_height, wp.cy);
-
- ret = DestroyWindow(hCombo);
- ok(ret, "DestroyWindow failed\n");
-}
-
-static LRESULT ComboExTestOnNotify(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- NMHDR *hdr = (NMHDR*)lParam;
- switch(hdr->code){
- case CBEN_ENDEDITA:
- {
- NMCBEENDEDITA *edit_info = (NMCBEENDEDITA*)hdr;
- if(edit_info->iWhy==CBENF_DROPDOWN){
- received_end_edit = TRUE;
- }
- break;
- }
- case CBEN_ENDEDITW:
- {
- NMCBEENDEDITW *edit_info = (NMCBEENDEDITW*)hdr;
- if(edit_info->iWhy==CBENF_DROPDOWN){
- received_end_edit = TRUE;
- }
- break;
- }
- }
- return 0;
-}
-
-static LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- switch(msg) {
-
- case WM_DESTROY:
- PostQuitMessage(0);
- break;
- case WM_NOTIFY:
- return ComboExTestOnNotify(hWnd,msg,wParam,lParam);
- default:
- return DefWindowProcA(hWnd, msg, wParam, lParam);
- }
-
- return 0L;
-}
-
-static BOOL init(void)
-{
- HMODULE hComctl32;
- BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
- WNDCLASSA wc;
- INITCOMMONCONTROLSEX iccex;
-
- hComctl32 = GetModuleHandleA("comctl32.dll");
- pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
- if (!pInitCommonControlsEx)
- {
- win_skip("InitCommonControlsEx() is missing. Skipping the tests\n");
- return FALSE;
- }
- iccex.dwSize = sizeof(iccex);
- iccex.dwICC = ICC_USEREX_CLASSES;
- pInitCommonControlsEx(&iccex);
-
- pSetWindowSubclass = (void*)GetProcAddress(hComctl32, (LPSTR)410);
-
- wc.style = CS_HREDRAW | CS_VREDRAW;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = GetModuleHandleA(NULL);
- wc.hIcon = NULL;
- wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
- wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = ComboExTestClass;
- wc.lpfnWndProc = ComboExTestWndProc;
- RegisterClassA(&wc);
-
- hComboExParentWnd = CreateWindowExA(0, ComboExTestClass, "ComboEx test", WS_OVERLAPPEDWINDOW|WS_VISIBLE,
- CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
- ok(hComboExParentWnd != NULL, "failed to create parent window\n");
-
- hMainHinst = GetModuleHandleA(NULL);
-
- return hComboExParentWnd != NULL;
-}
-
-static void cleanup(void)
-{
- MSG msg;
-
- PostMessageA(hComboExParentWnd, WM_CLOSE, 0, 0);
- while (GetMessageA(&msg,0,0,0)) {
- TranslateMessage(&msg);
- DispatchMessageA(&msg);
- }
-
- DestroyWindow(hComboExParentWnd);
- UnregisterClassA(ComboExTestClass, GetModuleHandleA(NULL));
-}
-
-static void test_comboboxex_subclass(void)
-{
- HWND hComboEx, hCombo, hEdit;
-
- hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
-
- hCombo = (HWND)SendMessageA(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0);
- ok(hCombo != NULL, "Failed to get internal combo\n");
- hEdit = (HWND)SendMessageA(hComboEx, CBEM_GETEDITCONTROL, 0, 0);
- ok(hEdit != NULL, "Failed to get internal edit\n");
-
- if (pSetWindowSubclass)
- {
- ok(GetPropA(hCombo, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n");
- ok(GetPropA(hEdit, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n");
- }
-
- DestroyWindow(hComboEx);
-}
-
-static const struct message test_setitem_edit_seq[] = {
- { WM_SETTEXT, sent|id, 0, 0, EDITBOX_ID },
- { EM_SETSEL, sent|id|wparam|lparam, 0, 0, EDITBOX_ID },
- { EM_SETSEL, sent|id|wparam|lparam, 0, -1, EDITBOX_ID },
- { 0 }
-};
-
-static void test_get_set_item(void)
-{
- char textA[] = "test";
- HWND hComboEx;
- COMBOBOXEXITEMA item;
- BOOL ret;
-
- hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
-
- subclass_editbox(hComboEx);
-
- flush_sequences(sequences, NUM_MSG_SEQUENCES);
-
- memset(&item, 0, sizeof(item));
- item.mask = CBEIF_TEXT;
- item.pszText = textA;
- item.iItem = -1;
- ret = SendMessageA(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item);
- expect(TRUE, ret);
-
- ok_sequence(sequences, EDITBOX_SEQ_INDEX, test_setitem_edit_seq, "set item data for edit", FALSE);
-
- /* get/set lParam */
- item.mask = CBEIF_LPARAM;
- item.iItem = -1;
- item.lParam = 0xdeadbeef;
- ret = SendMessageA(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item);
- expect(TRUE, ret);
- ok(item.lParam == 0, "Expected zero, got %lx\n", item.lParam);
-
- item.lParam = 0x1abe11ed;
- ret = SendMessageA(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item);
- expect(TRUE, ret);
-
- item.lParam = 0;
- ret = SendMessageA(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item);
- expect(TRUE, ret);
- ok(item.lParam == 0x1abe11ed, "Expected 0x1abe11ed, got %lx\n", item.lParam);
-
- DestroyWindow(hComboEx);
-}
-
-START_TEST(comboex)
-{
- if (!init())
- return;
-
- init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
-
- test_comboboxex();
- test_WM_LBUTTONDOWN();
- test_CB_GETLBTEXT();
- test_WM_WINDOWPOSCHANGING();
- test_comboboxex_subclass();
- test_get_set_item();
-
- cleanup();
-}
--- /dev/null
+/* Unit test suite for edit control.
+ *
+ * Copyright 2004 Vitaliy Margolen
+ * Copyright 2005 C. Scott Ananian
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "precomp.h"
+
+#ifndef ES_COMBO
+#define ES_COMBO 0x200
+#endif
+
+#define ID_EDITTESTDBUTTON 0x123
+#define ID_EDITTEST2 99
+#define MAXLEN 200
+
+struct edit_notify {
+ int en_change, en_maxtext, en_update;
+};
+
+static struct edit_notify notifications;
+
+static INT_PTR CALLBACK multi_edit_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ static int num_ok_commands = 0;
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ HWND hedit = GetDlgItem(hdlg, 1000);
+ SetFocus(hedit);
+ switch (lparam)
+ {
+ /* test cases related to bug 12319 */
+ case 0:
+ PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
+ break;
+ case 1:
+ PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
+ break;
+ case 2:
+ PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
+ break;
+
+ /* test cases for pressing enter */
+ case 3:
+ num_ok_commands = 0;
+ PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ case WM_COMMAND:
+ if (HIWORD(wparam) != BN_CLICKED)
+ break;
+
+ switch (LOWORD(wparam))
+ {
+ case IDOK:
+ num_ok_commands++;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case WM_USER:
+ {
+ HWND hfocus = GetFocus();
+ HWND hedit = GetDlgItem(hdlg, 1000);
+ HWND hedit2 = GetDlgItem(hdlg, 1001);
+ HWND hedit3 = GetDlgItem(hdlg, 1002);
+
+ if (wparam != 0xdeadbeef)
+ break;
+
+ switch (lparam)
+ {
+ case 0:
+ if (hfocus == hedit)
+ EndDialog(hdlg, 1111);
+ else if (hfocus == hedit2)
+ EndDialog(hdlg, 2222);
+ else if (hfocus == hedit3)
+ EndDialog(hdlg, 3333);
+ else
+ EndDialog(hdlg, 4444);
+ break;
+ case 1:
+ if ((hfocus == hedit) && (num_ok_commands == 0))
+ EndDialog(hdlg, 11);
+ else
+ EndDialog(hdlg, 22);
+ break;
+ default:
+ EndDialog(hdlg, 5555);
+ }
+ break;
+ }
+
+ case WM_CLOSE:
+ EndDialog(hdlg, 333);
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static INT_PTR CALLBACK edit_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ HWND hedit = GetDlgItem(hdlg, 1000);
+ SetFocus(hedit);
+ switch (lparam)
+ {
+ /* from bug 11841 */
+ case 0:
+ PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
+ break;
+ case 1:
+ PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
+ break;
+ case 2:
+ PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
+ break;
+
+ /* more test cases for WM_CHAR */
+ case 3:
+ PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
+ break;
+ case 4:
+ PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
+ break;
+ case 5:
+ PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
+ break;
+
+ /* more test cases for WM_KEYDOWN + WM_CHAR */
+ case 6:
+ PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
+ PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
+ break;
+ case 7:
+ PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
+ PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
+ break;
+ case 8:
+ PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
+ break;
+
+ /* multiple tab tests */
+ case 9:
+ PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 2);
+ break;
+ case 10:
+ PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 2);
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ case WM_COMMAND:
+ if (HIWORD(wparam) != BN_CLICKED)
+ break;
+
+ switch (LOWORD(wparam))
+ {
+ case IDOK:
+ EndDialog(hdlg, 111);
+ break;
+
+ case IDCANCEL:
+ EndDialog(hdlg, 222);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case WM_USER:
+ {
+ int len;
+ HWND hok = GetDlgItem(hdlg, IDOK);
+ HWND hcancel = GetDlgItem(hdlg, IDCANCEL);
+ HWND hedit = GetDlgItem(hdlg, 1000);
+ HWND hfocus = GetFocus();
+
+ if (wparam != 0xdeadbeef)
+ break;
+
+ switch (lparam)
+ {
+ case 0:
+ len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0);
+ if (len == 0)
+ EndDialog(hdlg, 444);
+ else
+ EndDialog(hdlg, 555);
+ break;
+
+ case 1:
+ len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0);
+ if ((hfocus == hok) && len == 0)
+ EndDialog(hdlg, 444);
+ else
+ EndDialog(hdlg, 555);
+ break;
+
+ case 2:
+ if (hfocus == hok)
+ EndDialog(hdlg, 11);
+ else if (hfocus == hcancel)
+ EndDialog(hdlg, 22);
+ else if (hfocus == hedit)
+ EndDialog(hdlg, 33);
+ else
+ EndDialog(hdlg, 44);
+ break;
+
+ default:
+ EndDialog(hdlg, 555);
+ }
+ break;
+ }
+
+ case WM_CLOSE:
+ EndDialog(hdlg, 333);
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static INT_PTR CALLBACK edit_singleline_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ HWND hedit = GetDlgItem(hdlg, 1000);
+ SetFocus(hedit);
+ switch (lparam)
+ {
+ /* test cases for WM_KEYDOWN */
+ case 0:
+ PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
+ break;
+ case 1:
+ PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
+ break;
+ case 2:
+ PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
+ break;
+
+ /* test cases for WM_CHAR */
+ case 3:
+ PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
+ break;
+ case 4:
+ PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
+ break;
+ case 5:
+ PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
+ break;
+
+ /* test cases for WM_KEYDOWN + WM_CHAR */
+ case 6:
+ PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
+ PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001);
+ break;
+ case 7:
+ PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
+ PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001);
+ break;
+ case 8:
+ PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ case WM_COMMAND:
+ if (HIWORD(wparam) != BN_CLICKED)
+ break;
+
+ switch (LOWORD(wparam))
+ {
+ case IDOK:
+ EndDialog(hdlg, 111);
+ break;
+
+ case IDCANCEL:
+ EndDialog(hdlg, 222);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case WM_USER:
+ {
+ HWND hok = GetDlgItem(hdlg, IDOK);
+ HWND hedit = GetDlgItem(hdlg, 1000);
+ HWND hfocus = GetFocus();
+ int len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0);
+
+ if (wparam != 0xdeadbeef)
+ break;
+
+ switch (lparam)
+ {
+ case 0:
+ if ((hfocus == hedit) && len == 0)
+ EndDialog(hdlg, 444);
+ else
+ EndDialog(hdlg, 555);
+ break;
+
+ case 1:
+ if ((hfocus == hok) && len == 0)
+ EndDialog(hdlg, 444);
+ else
+ EndDialog(hdlg, 555);
+ break;
+
+ default:
+ EndDialog(hdlg, 55);
+ }
+ break;
+ }
+
+ case WM_CLOSE:
+ EndDialog(hdlg, 333);
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static INT_PTR CALLBACK edit_wantreturn_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ HWND hedit = GetDlgItem(hdlg, 1000);
+ SetFocus(hedit);
+ switch (lparam)
+ {
+ /* test cases for WM_KEYDOWN */
+ case 0:
+ PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
+ break;
+ case 1:
+ PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
+ break;
+ case 2:
+ PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
+ break;
+
+ /* test cases for WM_CHAR */
+ case 3:
+ PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
+ break;
+ case 4:
+ PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 2);
+ break;
+ case 5:
+ PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
+ break;
+
+ /* test cases for WM_KEYDOWN + WM_CHAR */
+ case 6:
+ PostMessageA(hedit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
+ PostMessageA(hedit, WM_CHAR, VK_ESCAPE, 0x10001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 0);
+ break;
+ case 7:
+ PostMessageA(hedit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
+ PostMessageA(hedit, WM_CHAR, VK_RETURN, 0x1c0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 2);
+ break;
+ case 8:
+ PostMessageA(hedit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ PostMessageA(hedit, WM_CHAR, VK_TAB, 0xf0001);
+ PostMessageA(hdlg, WM_USER, 0xdeadbeef, 1);
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ case WM_COMMAND:
+ if (HIWORD(wparam) != BN_CLICKED)
+ break;
+
+ switch (LOWORD(wparam))
+ {
+ case IDOK:
+ EndDialog(hdlg, 111);
+ break;
+
+ case IDCANCEL:
+ EndDialog(hdlg, 222);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case WM_USER:
+ {
+ HWND hok = GetDlgItem(hdlg, IDOK);
+ HWND hedit = GetDlgItem(hdlg, 1000);
+ HWND hfocus = GetFocus();
+ int len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0);
+
+ if (wparam != 0xdeadbeef)
+ break;
+
+ switch (lparam)
+ {
+ case 0:
+ if ((hfocus == hedit) && len == 0)
+ EndDialog(hdlg, 444);
+ else
+ EndDialog(hdlg, 555);
+ break;
+
+ case 1:
+ if ((hfocus == hok) && len == 0)
+ EndDialog(hdlg, 444);
+ else
+ EndDialog(hdlg, 555);
+ break;
+
+ case 2:
+ if ((hfocus == hedit) && len == 2)
+ EndDialog(hdlg, 444);
+ else
+ EndDialog(hdlg, 555);
+ break;
+
+ default:
+ EndDialog(hdlg, 55);
+ }
+ break;
+ }
+
+ case WM_CLOSE:
+ EndDialog(hdlg, 333);
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static HINSTANCE hinst;
+static HWND hwndET2;
+static const char szEditTest2Class[] = "EditTest2Class";
+static const char szEditTest3Class[] = "EditTest3Class";
+static const char szEditTest4Class[] = "EditTest4Class";
+static const char szEditTextPositionClass[] = "EditTextPositionWindowClass";
+
+static HWND create_editcontrol (DWORD style, DWORD exstyle)
+{
+ HWND handle;
+
+ handle = CreateWindowExA(exstyle,
+ "EDIT",
+ "Test Text",
+ style,
+ 10, 10, 300, 300,
+ NULL, NULL, hinst, NULL);
+ ok (handle != NULL, "CreateWindow EDIT Control failed\n");
+ assert (handle);
+ if (winetest_interactive)
+ ShowWindow (handle, SW_SHOW);
+ return handle;
+}
+
+static HWND create_editcontrolW(DWORD style, DWORD exstyle)
+{
+ static const WCHAR testtextW[] = {'T','e','s','t',' ','t','e','x','t',0};
+ HWND handle;
+
+ handle = CreateWindowExW(exstyle, WC_EDITW, testtextW, style, 10, 10, 300, 300,
+ NULL, NULL, hinst, NULL);
+ ok(handle != NULL, "Failed to create Edit control.\n");
+ return handle;
+}
+
+static HWND create_child_editcontrol (DWORD style, DWORD exstyle)
+{
+ HWND parentWnd;
+ HWND editWnd;
+ RECT rect;
+ BOOL b;
+ SetRect(&rect, 0, 0, 300, 300);
+ b = AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
+ ok(b, "AdjustWindowRect failed\n");
+
+ parentWnd = CreateWindowExA(0,
+ szEditTextPositionClass,
+ "Edit Test",
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ rect.right - rect.left, rect.bottom - rect.top,
+ NULL, NULL, hinst, NULL);
+ ok (parentWnd != NULL, "CreateWindow EDIT Test failed\n");
+ assert(parentWnd);
+
+ editWnd = CreateWindowExA(exstyle,
+ "EDIT",
+ "Test Text",
+ WS_CHILD | style,
+ 0, 0, 300, 300,
+ parentWnd, NULL, hinst, NULL);
+ ok (editWnd != NULL, "CreateWindow EDIT Test Text failed\n");
+ assert(editWnd);
+ if (winetest_interactive)
+ ShowWindow (parentWnd, SW_SHOW);
+ return editWnd;
+}
+
+static void destroy_child_editcontrol (HWND hwndEdit)
+{
+ if (GetParent(hwndEdit))
+ DestroyWindow(GetParent(hwndEdit));
+ else {
+ trace("Edit control has no parent!\n");
+ DestroyWindow(hwndEdit);
+ }
+}
+
+static LONG get_edit_style (HWND hwnd)
+{
+ return GetWindowLongA( hwnd, GWL_STYLE ) & (
+ ES_LEFT |
+/* FIXME: not implemented
+ ES_CENTER |
+ ES_RIGHT |
+ ES_OEMCONVERT |
+*/
+ ES_MULTILINE |
+ ES_UPPERCASE |
+ ES_LOWERCASE |
+ ES_PASSWORD |
+ ES_AUTOVSCROLL |
+ ES_AUTOHSCROLL |
+ ES_NOHIDESEL |
+ ES_COMBO |
+ ES_READONLY |
+ ES_WANTRETURN |
+ ES_NUMBER
+ );
+}
+
+static void set_client_height(HWND Wnd, unsigned Height)
+{
+ RECT ClientRect, WindowRect;
+
+ GetWindowRect(Wnd, &WindowRect);
+ GetClientRect(Wnd, &ClientRect);
+ SetWindowPos(Wnd, NULL, 0, 0,
+ WindowRect.right - WindowRect.left,
+ Height + (WindowRect.bottom - WindowRect.top) -
+ (ClientRect.bottom - ClientRect.top),
+ SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
+
+ /* Workaround for a bug in Windows' edit control
+ (multi-line mode) */
+ GetWindowRect(Wnd, &WindowRect);
+ SetWindowPos(Wnd, NULL, 0, 0,
+ WindowRect.right - WindowRect.left + 1,
+ WindowRect.bottom - WindowRect.top + 1,
+ SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
+ SetWindowPos(Wnd, NULL, 0, 0,
+ WindowRect.right - WindowRect.left,
+ WindowRect.bottom - WindowRect.top,
+ SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
+
+ GetClientRect(Wnd, &ClientRect);
+ ok(ClientRect.bottom - ClientRect.top == Height,
+ "The client height should be %d, but is %d\n",
+ Height, ClientRect.bottom - ClientRect.top);
+}
+
+static void test_edit_control_1(void)
+{
+ HWND hwEdit;
+ MSG msMessage;
+ int i;
+ LONG r;
+
+ msMessage.message = WM_KEYDOWN;
+
+ trace("EDIT: Single line\n");
+ hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
+ r = get_edit_style(hwEdit);
+ ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL), "Wrong style expected 0xc0 got: 0x%x\n", r);
+ for (i = 0; i < 65535; i++)
+ {
+ msMessage.wParam = i;
+ r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
+ ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS),
+ "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %x\n", r);
+ }
+ DestroyWindow(hwEdit);
+
+ trace("EDIT: Single line want returns\n");
+ hwEdit = create_editcontrol(ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
+ r = get_edit_style(hwEdit);
+ ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN), "Wrong style expected 0x10c0 got: 0x%x\n", r);
+ for (i = 0; i < 65535; i++)
+ {
+ msMessage.wParam = i;
+ r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
+ ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS),
+ "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %x\n", r);
+ }
+ DestroyWindow(hwEdit);
+
+ trace("EDIT: Multiline line\n");
+ hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
+ r = get_edit_style(hwEdit);
+ ok(r == (ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0xc4 got: 0x%x\n", r);
+ for (i = 0; i < 65535; i++)
+ {
+ msMessage.wParam = i;
+ r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
+ ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS),
+ "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %x\n", r);
+ }
+ DestroyWindow(hwEdit);
+
+ trace("EDIT: Multi line want returns\n");
+ hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
+ r = get_edit_style(hwEdit);
+ ok(r == (ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0x10c4 got: 0x%x\n", r);
+ for (i = 0; i < 65535; i++)
+ {
+ msMessage.wParam = i;
+ r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
+ ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS),
+ "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %x\n", r);
+ }
+ DestroyWindow(hwEdit);
+}
+
+/* WM_SETTEXT is implemented by selecting all text, and then replacing the
+ * selection. This test checks that the first 'select all' doesn't generate
+ * an UPDATE message which can escape and (via a handler) change the
+ * selection, which would cause WM_SETTEXT to break. This old bug
+ * was fixed 18-Mar-2005; we check here to ensure it doesn't regress.
+ */
+static void test_edit_control_2(void)
+{
+ HWND hwndMain, phwnd;
+ char szLocalString[MAXLEN];
+ LONG r, w = 150, h = 50;
+ POINT cpos;
+
+ /* Create main and edit windows. */
+ hwndMain = CreateWindowA(szEditTest2Class, "ET2", WS_OVERLAPPEDWINDOW,
+ 0, 0, 200, 200, NULL, NULL, hinst, NULL);
+ assert(hwndMain);
+ if (winetest_interactive)
+ ShowWindow (hwndMain, SW_SHOW);
+
+ hwndET2 = CreateWindowA("EDIT", NULL,
+ WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL,
+ 0, 0, w, h, /* important this not be 0 size. */
+ hwndMain, (HMENU) ID_EDITTEST2, hinst, NULL);
+ assert(hwndET2);
+ if (winetest_interactive)
+ ShowWindow (hwndET2, SW_SHOW);
+
+ trace("EDIT: SETTEXT atomicity\n");
+ /* Send messages to "type" in the word 'foo'. */
+ r = SendMessageA(hwndET2, WM_CHAR, 'f', 1);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+ r = SendMessageA(hwndET2, WM_CHAR, 'o', 1);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+ r = SendMessageA(hwndET2, WM_CHAR, 'o', 1);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+ /* 'foo' should have been changed to 'bar' by the UPDATE handler. */
+ GetWindowTextA(hwndET2, szLocalString, MAXLEN);
+ ok(strcmp(szLocalString, "bar")==0,
+ "Wrong contents of edit: %s\n", szLocalString);
+
+ /* try setting the caret before it's visible */
+ r = SetCaretPos(0, 0);
+ todo_wine ok(0 == r, "SetCaretPos succeeded unexpectedly, expected: 0, got: %d\n", r);
+ phwnd = SetFocus(hwndET2);
+ ok(phwnd != NULL, "SetFocus failed unexpectedly, expected non-zero, got NULL\n");
+ r = SetCaretPos(0, 0);
+ ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r);
+ r = GetCaretPos(&cpos);
+ ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r);
+ ok(cpos.x == 0 && cpos.y == 0, "Wrong caret position, expected: (0,0), got: (%d,%d)\n", cpos.x, cpos.y);
+ r = SetCaretPos(-1, -1);
+ ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r);
+ r = GetCaretPos(&cpos);
+ ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r);
+ ok(cpos.x == -1 && cpos.y == -1, "Wrong caret position, expected: (-1,-1), got: (%d,%d)\n", cpos.x, cpos.y);
+ r = SetCaretPos(w << 1, h << 1);
+ ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r);
+ r = GetCaretPos(&cpos);
+ ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r);
+ ok(cpos.x == (w << 1) && cpos.y == (h << 1), "Wrong caret position, expected: (%d,%d), got: (%d,%d)\n", w << 1, h << 1, cpos.x, cpos.y);
+ r = SetCaretPos(w, h);
+ ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r);
+ r = GetCaretPos(&cpos);
+ ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r);
+ ok(cpos.x == w && cpos.y == h, "Wrong caret position, expected: (%d,%d), got: (%d,%d)\n", w, h, cpos.x, cpos.y);
+ r = SetCaretPos(w - 1, h - 1);
+ ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r);
+ r = GetCaretPos(&cpos);
+ ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r);
+ ok(cpos.x == (w - 1) && cpos.y == (h - 1), "Wrong caret position, expected: (%d,%d), got: (%d,%d)\n", w - 1, h - 1, cpos.x, cpos.y);
+
+ DestroyWindow(hwndET2);
+ DestroyWindow(hwndMain);
+}
+
+static void ET2_check_change(void)
+{
+ char szLocalString[MAXLEN];
+ /* This EN_UPDATE handler changes any 'foo' to 'bar'. */
+ GetWindowTextA(hwndET2, szLocalString, MAXLEN);
+ if (!strcmp(szLocalString, "foo"))
+ {
+ strcpy(szLocalString, "bar");
+ SendMessageA(hwndET2, WM_SETTEXT, 0, (LPARAM)szLocalString);
+ }
+ /* always leave the cursor at the end. */
+ SendMessageA(hwndET2, EM_SETSEL, MAXLEN - 1, MAXLEN - 1);
+}
+
+static void ET2_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
+{
+ if (id == ID_EDITTEST2 && codeNotify == EN_UPDATE)
+ ET2_check_change();
+}
+
+static LRESULT CALLBACK ET2_WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (iMsg)
+ {
+ case WM_COMMAND:
+ ET2_OnCommand(hwnd, LOWORD(wParam), (HWND)lParam, HIWORD(wParam));
+ break;
+ }
+ return DefWindowProcA(hwnd, iMsg, wParam, lParam);
+}
+
+static void zero_notify(void)
+{
+ notifications.en_change = 0;
+ notifications.en_maxtext = 0;
+ notifications.en_update = 0;
+}
+
+#define test_notify(enchange, enmaxtext, enupdate) \
+do { \
+ ok(notifications.en_change == enchange, "expected %d EN_CHANGE notifications, " \
+ "got %d\n", enchange, notifications.en_change); \
+ ok(notifications.en_maxtext == enmaxtext, "expected %d EN_MAXTEXT notifications, " \
+ "got %d\n", enmaxtext, notifications.en_maxtext); \
+ ok(notifications.en_update == enupdate, "expected %d EN_UPDATE notifications, " \
+ "got %d\n", enupdate, notifications.en_update); \
+} while(0)
+
+static LRESULT CALLBACK edit3_wnd_procA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_COMMAND:
+ switch (HIWORD(wParam))
+ {
+ case EN_MAXTEXT:
+ notifications.en_maxtext++;
+ break;
+ case EN_UPDATE:
+ notifications.en_update++;
+ break;
+ case EN_CHANGE:
+ notifications.en_change++;
+ break;
+ }
+ break;
+ }
+ return DefWindowProcA(hWnd, msg, wParam, lParam);
+}
+
+/* Test behaviour of WM_SETTEXT, WM_REPLACESEL and notifications sent in response
+ * to these messages.
+ */
+static void test_edit_control_3(void)
+{
+ static const char *str = "this is a long string.";
+ static const char *str2 = "this is a long string.\r\nthis is a long string.\r\nthis is a long string.\r\nthis is a long string.";
+ HWND hWnd, hParent;
+ int len, dpi;
+ HDC hDC;
+
+ hDC = GetDC(NULL);
+ dpi = GetDeviceCaps(hDC, LOGPIXELSY);
+ ReleaseDC(NULL, hDC);
+
+ trace("EDIT: Test notifications\n");
+
+ hParent = CreateWindowExA(0,
+ szEditTest3Class,
+ NULL,
+ 0,
+ CW_USEDEFAULT, CW_USEDEFAULT, 10, 10,
+ NULL, NULL, NULL, NULL);
+ assert(hParent);
+
+ trace("EDIT: Single line, no ES_AUTOHSCROLL\n");
+ hWnd = CreateWindowExA(0,
+ "EDIT",
+ NULL,
+ 0,
+ 10, 10, 50, 50,
+ hParent, NULL, NULL, NULL);
+ assert(hWnd);
+
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ if (len == lstrlenA(str)) /* Win 8 */
+ test_notify(1, 0, 1);
+ else
+ test_notify(1, 1, 1);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(1 == len, "wrong text length, expected 1, got %d\n", len);
+ test_notify(1, 0, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ test_notify(1, 0, 1);
+
+ len = SendMessageA(hWnd, EM_GETSEL, 0, 0);
+ ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
+ ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len));
+ SendMessageA(hParent, WM_SETFOCUS, 0, (LPARAM)hWnd);
+ len = SendMessageA(hWnd, EM_GETSEL, 0, 0);
+ ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
+ ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len));
+
+ SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
+ test_notify(1, 1, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ test_notify(1, 0, 1);
+
+ DestroyWindow(hWnd);
+
+ trace("EDIT: Single line, ES_AUTOHSCROLL\n");
+ hWnd = CreateWindowExA(0,
+ "EDIT",
+ NULL,
+ ES_AUTOHSCROLL,
+ 10, 10, 50, 50,
+ hParent, NULL, NULL, NULL);
+ assert(hWnd);
+
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ test_notify(1, 0, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ test_notify(1, 0, 1);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
+ test_notify(1, 0, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
+ test_notify(1, 0, 1);
+
+ SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
+ test_notify(1, 1, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ test_notify(1, 0, 1);
+
+ DestroyWindow(hWnd);
+
+ trace("EDIT: Multline, no ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n");
+ hWnd = CreateWindowExA(0,
+ "EDIT",
+ NULL,
+ ES_MULTILINE,
+ 10, 10, (50 * dpi) / 96, (50 * dpi) / 96,
+ hParent, NULL, NULL, NULL);
+ assert(hWnd);
+
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ if (len == lstrlenA(str)) /* Win 8 */
+ test_notify(1, 0, 1);
+ else
+ {
+ ok(0 == len, "text should have been truncated, expected 0, got %d\n", len);
+ test_notify(1, 1, 1);
+ }
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len);
+ test_notify(1, 0, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ test_notify(0, 0, 0);
+
+ SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
+ test_notify(1, 1, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ test_notify(0, 0, 0);
+
+ DestroyWindow(hWnd);
+
+ trace("EDIT: Multline, ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n");
+ hWnd = CreateWindowExA(0,
+ "EDIT",
+ NULL,
+ ES_MULTILINE | ES_AUTOHSCROLL,
+ 10, 10, (50 * dpi) / 96, (50 * dpi) / 96,
+ hParent, NULL, NULL, NULL);
+ assert(hWnd);
+
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(0 == len, "text should have been truncated, expected 0, got %d\n", len);
+ test_notify(1, 1, 1);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len);
+ test_notify(1, 0, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
+ test_notify(0, 0, 0);
+
+ SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
+ test_notify(1, 1, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
+ test_notify(0, 0, 0);
+
+ DestroyWindow(hWnd);
+
+ trace("EDIT: Multline, ES_AUTOHSCROLL and ES_AUTOVSCROLL\n");
+ hWnd = CreateWindowExA(0,
+ "EDIT",
+ NULL,
+ ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
+ 10, 10, 50, 50,
+ hParent, NULL, NULL, NULL);
+ assert(hWnd);
+
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
+ test_notify(1, 0, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
+ test_notify(0, 0, 0);
+
+ SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
+ test_notify(1, 1, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
+ test_notify(0, 0, 0);
+
+ DestroyWindow(hWnd);
+}
+
+static void test_char_from_pos(void)
+{
+ int lo, hi, mid, ret, i;
+ HWND hwEdit;
+
+ hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
+ SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa");
+ lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0));
+ hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0));
+ mid = lo + (hi - lo) / 2;
+
+ for (i = lo; i < mid; i++)
+ {
+ ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
+ ok(0 == ret, "expected 0 got %d\n", ret);
+ }
+
+ for (i = mid; i <= hi; i++)
+ {
+ ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
+ ok(1 == ret, "expected 1 got %d\n", ret);
+ }
+
+ ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0);
+ ok(-1 == ret, "expected -1 got %d\n", ret);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(ES_RIGHT | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
+ SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa");
+ lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0));
+ hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0));
+ mid = lo + (hi - lo) / 2;
+
+ for (i = lo; i < mid; i++)
+ {
+ ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
+ ok(0 == ret, "expected 0 got %d\n", ret);
+ }
+
+ for (i = mid; i <= hi; i++)
+ {
+ ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
+ ok(1 == ret, "expected 1 got %d\n", ret);
+ }
+
+ ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0);
+ ok(-1 == ret, "expected -1 got %d\n", ret);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(ES_CENTER | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
+ SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa");
+ lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0));
+ hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0));
+ mid = lo + (hi - lo) / 2;
+
+ for (i = lo; i < mid; i++)
+ {
+ ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
+ ok(0 == ret, "expected 0 got %d\n", ret);
+ }
+
+ for (i = mid; i <= hi; i++)
+ {
+ ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
+ ok(1 == ret, "expected 1 got %d\n", ret);
+ }
+
+ ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0);
+ ok(-1 == ret, "expected -1 got %d\n", ret);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
+ SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa");
+ lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0));
+ hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0));
+ mid = lo + (hi - lo) / 2 + 1;
+
+ for (i = lo; i < mid; i++)
+ {
+ ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
+ ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret);
+ }
+
+ for (i = mid; i <= hi; i++)
+ {
+ ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
+ ok(1 == ret, "expected 1 got %d\n", ret);
+ }
+
+ ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0);
+ ok(-1 == ret, "expected -1 got %d\n", ret);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(ES_MULTILINE | ES_RIGHT | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
+ SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa");
+ lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0));
+ hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0));
+ mid = lo + (hi - lo) / 2 + 1;
+
+ for (i = lo; i < mid; i++)
+ {
+ ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
+ ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret);
+ }
+
+ for (i = mid; i <= hi; i++)
+ {
+ ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
+ ok(1 == ret, "expected 1 got %d\n", ret);
+ }
+
+ ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0);
+ ok(-1 == ret, "expected -1 got %d\n", ret);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(ES_MULTILINE | ES_CENTER | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
+ SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"aa");
+ lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0));
+ hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0));
+ mid = lo + (hi - lo) / 2 + 1;
+
+ for (i = lo; i < mid; i++)
+ {
+ ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
+ ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret);
+ }
+
+ for (i = mid; i <= hi; i++)
+ {
+ ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i));
+ ok(1 == ret, "expected 1 got %d\n", ret);
+ }
+
+ ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0);
+ ok(-1 == ret, "expected -1 got %d\n", ret);
+ DestroyWindow(hwEdit);
+}
+
+/* Test if creating edit control without ES_AUTOHSCROLL and ES_AUTOVSCROLL
+ * truncates text that doesn't fit.
+ */
+static void test_edit_control_5(void)
+{
+ static const char *str = "test\r\ntest";
+ HWND parentWnd;
+ HWND hWnd;
+ int len;
+ RECT rc1 = { 10, 10, 11, 11};
+ RECT rc;
+
+ /* first show that a non-child won't do for this test */
+ hWnd = CreateWindowExA(0,
+ "EDIT",
+ str,
+ 0,
+ 10, 10, 1, 1,
+ NULL, NULL, NULL, NULL);
+ assert(hWnd);
+ /* size of non-child edit control is (much) bigger than requested */
+ GetWindowRect( hWnd, &rc);
+ ok( rc.right - rc.left > 20, "size of the window (%d) is smaller than expected\n",
+ rc.right - rc.left);
+ DestroyWindow(hWnd);
+ /* so create a parent, and give it edit controls children to test with */
+ parentWnd = CreateWindowExA(0,
+ szEditTextPositionClass,
+ "Edit Test", WS_VISIBLE |
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ 250, 250,
+ NULL, NULL, hinst, NULL);
+ assert(parentWnd);
+ ShowWindow( parentWnd, SW_SHOW);
+ /* single line */
+ hWnd = CreateWindowExA(0,
+ "EDIT",
+ str, WS_VISIBLE | WS_BORDER |
+ WS_CHILD,
+ rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top,
+ parentWnd, NULL, NULL, NULL);
+ assert(hWnd);
+ GetClientRect( hWnd, &rc);
+ ok( rc.right == rc1.right - rc1.left && rc.bottom == rc1.bottom - rc1.top,
+ "Client rectangle not the expected size %s\n", wine_dbgstr_rect( &rc ));
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ DestroyWindow(hWnd);
+ /* multi line */
+ hWnd = CreateWindowExA(0,
+ "EDIT",
+ str,
+ WS_CHILD | ES_MULTILINE,
+ rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top,
+ parentWnd, NULL, NULL, NULL);
+ assert(hWnd);
+ GetClientRect( hWnd, &rc);
+ ok( rc.right == rc1.right - rc1.left && rc.bottom == rc1.bottom - rc1.top,
+ "Client rectangle not the expected size %s\n", wine_dbgstr_rect( &rc ));
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ DestroyWindow(hWnd);
+ DestroyWindow(parentWnd);
+}
+
+/* Test WM_GETTEXT processing
+ * after destroy messages
+ */
+static void test_edit_control_6(void)
+{
+ static const char *str = "test\r\ntest";
+ char buf[MAXLEN];
+ HWND hWnd;
+ LONG ret;
+
+ hWnd = CreateWindowExA(0, "EDIT", "Test", 0, 10, 10, 1, 1, NULL, NULL, hinst, NULL);
+ ok(hWnd != NULL, "Failed to create edit control.\n");
+
+ ret = SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
+ ok(ret == TRUE, "Expected %d, got %d\n", TRUE, ret);
+ ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf);
+ ok(ret == strlen(str), "Expected %s, got len %d\n", str, ret);
+ ok(!strcmp(buf, str), "Expected %s, got %s\n", str, buf);
+
+ buf[0] = 0;
+ ret = SendMessageA(hWnd, WM_DESTROY, 0, 0);
+todo_wine
+ ok(ret == 1, "Unexpected return value %d\n", ret);
+ ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf);
+ ok(ret == strlen(str), "Expected %s, got len %d\n", str, ret);
+ ok(!strcmp(buf, str), "Expected %s, got %s\n", str, buf);
+
+ buf[0] = 0;
+ ret = SendMessageA(hWnd, WM_NCDESTROY, 0, 0);
+ ok(ret == 0, "Expected 0, got %d\n", ret);
+ ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf);
+todo_wine {
+ ok(ret == strlen("Test"), "Unexpected text length %d\n", ret);
+ ok(!strcmp(buf, "Test"), "Unexpected text %s\n", buf);
+}
+ DestroyWindow(hWnd);
+}
+
+static void test_edit_control_limittext(void)
+{
+ HWND hwEdit;
+ DWORD r;
+
+ /* Test default limit for single-line control */
+ trace("EDIT: buffer limit for single-line\n");
+ hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
+ r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0);
+ ok(r == 30000, "Incorrect default text limit, expected 30000 got %u\n", r);
+ SendMessageA(hwEdit, EM_SETLIMITTEXT, 0, 0);
+ r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0);
+ ok( r == 2147483646, "got limit %u (expected 2147483646)\n", r);
+ DestroyWindow(hwEdit);
+
+ /* Test default limit for multi-line control */
+ trace("EDIT: buffer limit for multi-line\n");
+ hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
+ r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0);
+ ok(r == 30000, "Incorrect default text limit, expected 30000 got %u\n", r);
+ SendMessageA(hwEdit, EM_SETLIMITTEXT, 0, 0);
+ r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0);
+ ok( r == 4294967295U, "got limit %u (expected 4294967295)\n", r);
+ DestroyWindow(hwEdit);
+}
+
+/* Test EM_SCROLL */
+static void test_edit_control_scroll(void)
+{
+ static const char *single_line_str = "a";
+ static const char *multiline_str = "Test\r\nText";
+ HWND hwEdit;
+ LONG ret;
+
+ /* Check the return value when EM_SCROLL doesn't scroll
+ * anything. Should not return true unless any lines were actually
+ * scrolled. */
+ hwEdit = CreateWindowA(
+ "EDIT",
+ single_line_str,
+ WS_VSCROLL | ES_MULTILINE,
+ 1, 1, 100, 100,
+ NULL, NULL, hinst, NULL);
+
+ assert(hwEdit);
+
+ ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEDOWN, 0);
+ ok(!ret, "Returned %x, expected 0.\n", ret);
+
+ ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEUP, 0);
+ ok(!ret, "Returned %x, expected 0.\n", ret);
+
+ ret = SendMessageA(hwEdit, EM_SCROLL, SB_LINEUP, 0);
+ ok(!ret, "Returned %x, expected 0.\n", ret);
+
+ ret = SendMessageA(hwEdit, EM_SCROLL, SB_LINEDOWN, 0);
+ ok(!ret, "Returned %x, expected 0.\n", ret);
+
+ DestroyWindow (hwEdit);
+
+ /* SB_PAGEDOWN while at the beginning of a buffer with few lines
+ should not cause EM_SCROLL to return a negative value of
+ scrolled lines that would put us "before" the beginning. */
+ hwEdit = CreateWindowA(
+ "EDIT",
+ multiline_str,
+ WS_VSCROLL | ES_MULTILINE,
+ 0, 0, 100, 100,
+ NULL, NULL, hinst, NULL);
+ assert(hwEdit);
+
+ ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEDOWN, 0);
+ ok(!ret, "Returned %x, expected 0.\n", ret);
+
+ DestroyWindow (hwEdit);
+}
+
+static void test_margins_usefontinfo(UINT charset)
+{
+ INT margins, threshold, expect, empty_expect, small_expect;
+ HWND hwnd;
+ HDC hdc;
+ SIZE size;
+ BOOL cjk;
+ LOGFONTA lf;
+ HFONT hfont;
+ RECT rect;
+
+ memset(&lf, 0, sizeof(lf));
+ lf.lfHeight = -11;
+ lf.lfWeight = FW_NORMAL;
+ lf.lfCharSet = charset;
+ strcpy(lf.lfFaceName, "Tahoma");
+
+ hfont = CreateFontIndirectA(&lf);
+ ok(hfont != NULL, "got %p\n", hfont);
+
+ /* Big window rectangle */
+ hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 5000, 1000, NULL, NULL, NULL, NULL);
+ ok(hwnd != NULL, "got %p\n", hwnd);
+ GetClientRect(hwnd, &rect);
+ ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect));
+
+ hdc = GetDC(hwnd);
+ hfont = SelectObject(hdc, hfont);
+ size.cx = GdiGetCharDimensions( hdc, NULL, &size.cy );
+ expect = MAKELONG(size.cx / 2, size.cx / 2);
+ small_expect = 0;
+ empty_expect = size.cx >= 28 ? small_expect : expect;
+
+ charset = GetTextCharset(hdc);
+ switch (charset)
+ {
+ case SHIFTJIS_CHARSET:
+ case HANGUL_CHARSET:
+ case GB2312_CHARSET:
+ case CHINESEBIG5_CHARSET:
+ cjk = TRUE;
+ break;
+ default:
+ cjk = FALSE;
+ }
+
+ hfont = SelectObject(hdc, hfont);
+ ReleaseDC(hwnd, hdc);
+
+ margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
+ ok(margins == 0, "got %x\n", margins);
+ SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
+ margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
+ if (!cjk)
+ ok(margins == expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins));
+ else
+ {
+ ok(HIWORD(margins) > 0 && LOWORD(margins) > 0, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins));
+ expect = empty_expect = small_expect = margins;
+ }
+ DestroyWindow(hwnd);
+
+ threshold = (size.cx / 2 + size.cx) * 2;
+
+ /* Size below which non-cjk margins are zero */
+ hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, threshold - 1, 100, NULL, NULL, NULL, NULL);
+ ok(hwnd != NULL, "got %p\n", hwnd);
+ GetClientRect(hwnd, &rect);
+ ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect));
+
+ margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
+ ok(margins == 0, "got %x\n", margins);
+
+ SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
+ margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
+ ok(margins == small_expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins));
+ DestroyWindow(hwnd);
+
+ /* Size at which non-cjk margins become non-zero */
+ hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, threshold, 100, NULL, NULL, NULL, NULL);
+ ok(hwnd != NULL, "got %p\n", hwnd);
+ GetClientRect(hwnd, &rect);
+ ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect));
+
+ margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
+ ok(margins == 0, "got %x\n", margins);
+
+ SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
+ margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
+ ok(margins == expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins));
+ DestroyWindow(hwnd);
+
+ /* Empty rect */
+ hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+ ok(hwnd != NULL, "got %p\n", hwnd);
+ GetClientRect(hwnd, &rect);
+ ok(IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect));
+
+ margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
+ ok(margins == 0, "got %x\n", margins);
+
+ SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
+ margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
+ ok(margins == empty_expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins));
+ DestroyWindow(hwnd);
+
+ DeleteObject(hfont);
+}
+
+static void test_margins(void)
+{
+ DWORD old_margins, new_margins;
+ RECT old_rect, new_rect;
+ INT old_right_margin;
+ HWND hwEdit;
+
+ hwEdit = create_editcontrol(WS_BORDER | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
+
+ old_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
+ old_right_margin = HIWORD(old_margins);
+
+ /* Check if setting the margins works */
+
+ SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN, MAKELONG(10, 0));
+ new_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
+ ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
+ ok(HIWORD(new_margins) == old_right_margin, "Wrong right margin: %d\n", HIWORD(new_margins));
+
+ SendMessageA(hwEdit, EM_SETMARGINS, EC_RIGHTMARGIN, MAKELONG(0, 10));
+ new_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
+ ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
+ ok(HIWORD(new_margins) == 10, "Wrong right margin: %d\n", HIWORD(new_margins));
+
+ /* The size of the rectangle must decrease if we increase the margin */
+
+ SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(5, 5));
+ SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
+ SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(15, 20));
+ SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
+ ok(new_rect.left == old_rect.left + 10, "The left border of the rectangle is wrong\n");
+ ok(new_rect.right == old_rect.right - 15, "The right border of the rectangle is wrong\n");
+ ok(new_rect.top == old_rect.top, "The top border of the rectangle must not change\n");
+ ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle must not change\n");
+
+ /* If we set the margin to same value as the current margin,
+ the rectangle must not change */
+
+ SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
+ SetRect(&old_rect, 1, 1, 99, 99);
+ SendMessageA(hwEdit, EM_SETRECT, 0, (LPARAM)&old_rect);
+ SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
+ SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
+ SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
+ ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n");
+
+ /* The lParam argument of the WM_SIZE message should be ignored. */
+
+ SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
+ SendMessageA(hwEdit, WM_SIZE, SIZE_RESTORED, 0);
+ SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
+ ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n");
+ SendMessageA(hwEdit, WM_SIZE, SIZE_MINIMIZED, 0);
+ SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
+ ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n");
+ SendMessageA(hwEdit, WM_SIZE, SIZE_MAXIMIZED, 0);
+ SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
+ ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n");
+ SendMessageA(hwEdit, WM_SIZE, SIZE_RESTORED, MAKELONG(10, 10));
+ SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
+ ok(EqualRect(&old_rect, &new_rect), "The border of the rectangle has changed\n");
+
+ DestroyWindow (hwEdit);
+
+ test_margins_usefontinfo(ANSI_CHARSET);
+ test_margins_usefontinfo(EASTEUROPE_CHARSET);
+
+ test_margins_usefontinfo(SHIFTJIS_CHARSET);
+ test_margins_usefontinfo(HANGUL_CHARSET);
+ test_margins_usefontinfo(CHINESEBIG5_CHARSET);
+ /* Don't test JOHAB_CHARSET. Treated as CJK by Win 8,
+ but not by < Win 8 and Win 10. */
+
+ test_margins_usefontinfo(DEFAULT_CHARSET);
+}
+
+static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
+{
+ return 0;
+}
+
+static void test_margins_font_change(void)
+{
+ DWORD margins, font_margins, ret;
+ HFONT hfont, hfont2;
+ HWND hwEdit;
+ LOGFONTA lf;
+ HDC hdc;
+
+ hdc = GetDC(0);
+ ret = EnumFontFamiliesA(hdc, "Arial", find_font_proc, 0);
+ ReleaseDC(0, hdc);
+ if (ret)
+ {
+ trace("Arial not found - skipping font change margin tests\n");
+ return;
+ }
+
+ hwEdit = create_child_editcontrol(0, 0);
+
+ SetWindowPos(hwEdit, NULL, 10, 10, 1000, 100, SWP_NOZORDER | SWP_NOACTIVATE);
+
+ memset(&lf, 0, sizeof(lf));
+ strcpy(lf.lfFaceName, "Arial");
+ lf.lfHeight = 16;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ hfont = CreateFontIndirectA(&lf);
+ lf.lfHeight = 30;
+ hfont2 = CreateFontIndirectA(&lf);
+
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
+ font_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
+ ok(LOWORD(font_margins) != 0, "got %d\n", LOWORD(font_margins));
+ ok(HIWORD(font_margins) != 0, "got %d\n", HIWORD(font_margins));
+
+ /* With 'small' edit controls, test that the margin doesn't get set */
+ SetWindowPos(hwEdit, NULL, 10, 10, 16, 100, SWP_NOZORDER | SWP_NOACTIVATE);
+ SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0,0));
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
+ margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
+ ok(LOWORD(margins) == 0, "got %d\n", LOWORD(margins));
+ ok(HIWORD(margins) == 0, "got %d\n", HIWORD(margins));
+
+ SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,0));
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
+ margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
+ ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
+ ok(HIWORD(margins) == 0, "got %d\n", HIWORD(margins));
+
+ SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,1));
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
+ margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
+ ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
+ ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins));
+
+ SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO,EC_USEFONTINFO));
+ margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
+ ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
+ ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins));
+
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont2, 0);
+ margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
+ ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
+ ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins));
+
+ /* Above a certain size threshold then the margin is updated */
+ SetWindowPos(hwEdit, NULL, 10, 10, 1000, 100, SWP_NOZORDER | SWP_NOACTIVATE);
+ SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,0));
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
+ margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
+ ok(LOWORD(margins) == LOWORD(font_margins), "got %d\n", LOWORD(margins));
+ ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins));
+
+ SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,1));
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
+ margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
+ ok(LOWORD(margins) == LOWORD(font_margins), "got %d\n", LOWORD(margins));
+ ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins));
+
+ SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO,EC_USEFONTINFO));
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
+ margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
+ ok(LOWORD(margins) == LOWORD(font_margins), "got %d\n", LOWORD(margins));
+ ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins));
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont2, 0);
+ margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0);
+ ok(LOWORD(margins) != LOWORD(font_margins), "got %d\n", LOWORD(margins));
+ ok(HIWORD(margins) != HIWORD(font_margins), "got %d\n", HIWORD(margins));
+
+ SendMessageA(hwEdit, WM_SETFONT, 0, 0);
+
+ DeleteObject(hfont2);
+ DeleteObject(hfont);
+ destroy_child_editcontrol(hwEdit);
+
+}
+
+#define edit_pos_ok(exp, got, txt) \
+ ok(exp == got, "wrong " #txt " expected %d got %d\n", exp, got);
+
+#define check_pos(hwEdit, set_height, test_top, test_height, test_left) \
+do { \
+ RECT format_rect; \
+ int left_margin; \
+ set_client_height(hwEdit, set_height); \
+ SendMessageA(hwEdit, EM_GETRECT, 0, (LPARAM) &format_rect); \
+ left_margin = LOWORD(SendMessageA(hwEdit, EM_GETMARGINS, 0, 0)); \
+ edit_pos_ok(test_top, format_rect.top, vertical position); \
+ edit_pos_ok((int)test_height, format_rect.bottom - format_rect.top, height); \
+ edit_pos_ok(test_left, format_rect.left - left_margin, left); \
+} while(0)
+
+static void test_text_position_style(DWORD style)
+{
+ HWND hwEdit;
+ HFONT font, oldFont;
+ HDC dc;
+ TEXTMETRICA metrics;
+ INT b, bm, b2, b3;
+ BOOL xb, single_line = !(style & ES_MULTILINE);
+
+ b = GetSystemMetrics(SM_CYBORDER) + 1;
+ b2 = 2 * b;
+ b3 = 3 * b;
+ bm = b2 - 1;
+
+ /* Get a stock font for which we can determine the metrics */
+ font = GetStockObject(SYSTEM_FONT);
+ ok (font != NULL, "GetStockObject SYSTEM_FONT failed\n");
+ dc = GetDC(NULL);
+ ok (dc != NULL, "GetDC() failed\n");
+ oldFont = SelectObject(dc, font);
+ xb = GetTextMetricsA(dc, &metrics);
+ ok (xb, "GetTextMetrics failed\n");
+ SelectObject(dc, oldFont);
+ ReleaseDC(NULL, dc);
+
+ /* Windows' edit control has some bugs in multi-line mode:
+ * - Sometimes the format rectangle doesn't get updated
+ * (see workaround in set_client_height())
+ * - If the height of the control is smaller than the height of a text
+ * line, the format rectangle is still as high as a text line
+ * (higher than the client rectangle) and the caret is not shown
+ */
+
+ /* Edit controls that are in a parent window */
+
+ hwEdit = create_child_editcontrol(style | WS_VISIBLE, 0);
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
+ if (single_line)
+ check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 0);
+ check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 0);
+ check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 0);
+ check_pos(hwEdit, metrics.tmHeight + 2, 0, metrics.tmHeight , 0);
+ check_pos(hwEdit, metrics.tmHeight + 10, 0, metrics.tmHeight , 0);
+ destroy_child_editcontrol(hwEdit);
+
+ hwEdit = create_child_editcontrol(style | WS_BORDER | WS_VISIBLE, 0);
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
+ if (single_line)
+ check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, b);
+ check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , b);
+ check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , b);
+ check_pos(hwEdit, metrics.tmHeight + bm, 0, metrics.tmHeight , b);
+ check_pos(hwEdit, metrics.tmHeight + b2, b, metrics.tmHeight , b);
+ check_pos(hwEdit, metrics.tmHeight + b3, b, metrics.tmHeight , b);
+ destroy_child_editcontrol(hwEdit);
+
+ hwEdit = create_child_editcontrol(style | WS_VISIBLE, WS_EX_CLIENTEDGE);
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
+ if (single_line)
+ check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1);
+ check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1);
+ check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1);
+ check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1);
+ check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1);
+ destroy_child_editcontrol(hwEdit);
+
+ hwEdit = create_child_editcontrol(style | WS_BORDER | WS_VISIBLE, WS_EX_CLIENTEDGE);
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
+ if (single_line)
+ check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1);
+ check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1);
+ check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1);
+ check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1);
+ check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1);
+ destroy_child_editcontrol(hwEdit);
+
+
+ /* Edit controls that are popup windows */
+
+ hwEdit = create_editcontrol(style | WS_POPUP, 0);
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
+ if (single_line)
+ check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 0);
+ check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 0);
+ check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 0);
+ check_pos(hwEdit, metrics.tmHeight + 2, 0, metrics.tmHeight , 0);
+ check_pos(hwEdit, metrics.tmHeight + 10, 0, metrics.tmHeight , 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(style | WS_POPUP | WS_BORDER, 0);
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
+ if (single_line)
+ check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, b);
+ check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , b);
+ check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , b);
+ check_pos(hwEdit, metrics.tmHeight + bm, 0, metrics.tmHeight , b);
+ check_pos(hwEdit, metrics.tmHeight + b2, b, metrics.tmHeight , b);
+ check_pos(hwEdit, metrics.tmHeight + b3, b, metrics.tmHeight , b);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(style | WS_POPUP, WS_EX_CLIENTEDGE);
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
+ if (single_line)
+ check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1);
+ check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1);
+ check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1);
+ check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1);
+ check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(style | WS_POPUP | WS_BORDER, WS_EX_CLIENTEDGE);
+ SendMessageA(hwEdit, WM_SETFONT, (WPARAM) font, FALSE);
+ if (single_line)
+ check_pos(hwEdit, metrics.tmHeight - 1, 0, metrics.tmHeight - 1, 1);
+ check_pos(hwEdit, metrics.tmHeight , 0, metrics.tmHeight , 1);
+ check_pos(hwEdit, metrics.tmHeight + 1, 0, metrics.tmHeight , 1);
+ check_pos(hwEdit, metrics.tmHeight + 2, 1, metrics.tmHeight , 1);
+ check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight , 1);
+ DestroyWindow(hwEdit);
+}
+
+static void test_text_position(void)
+{
+ trace("EDIT: Text position (Single line)\n");
+ test_text_position_style(ES_AUTOHSCROLL | ES_AUTOVSCROLL);
+ trace("EDIT: Text position (Multi line)\n");
+ test_text_position_style(ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL);
+}
+
+static void test_espassword(void)
+{
+ HWND hwEdit;
+ LONG r;
+ char buffer[1024];
+ const char* password = "secret";
+
+ hwEdit = create_editcontrol(ES_PASSWORD, 0);
+ r = get_edit_style(hwEdit);
+ ok(r == ES_PASSWORD, "Wrong style expected ES_PASSWORD got: 0x%x\n", r);
+ /* set text */
+ r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) password);
+ ok(r == TRUE, "Expected: %d, got: %d\n", TRUE, r);
+
+ /* select all, cut (ctrl-x) */
+ SendMessageA(hwEdit, EM_SETSEL, 0, -1);
+ r = SendMessageA(hwEdit, WM_CHAR, 24, 0);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+
+ /* get text */
+ r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
+ ok(r == strlen(password), "Expected: %s, got len %d\n", password, r);
+ ok(strcmp(buffer, password) == 0, "expected %s, got %s\n", password, buffer);
+
+ r = OpenClipboard(hwEdit);
+ ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
+ r = EmptyClipboard();
+ ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
+ r = CloseClipboard();
+ ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
+
+ /* select all, copy (ctrl-c) and paste (ctrl-v) */
+ SendMessageA(hwEdit, EM_SETSEL, 0, -1);
+ r = SendMessageA(hwEdit, WM_CHAR, 3, 0);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+ r = SendMessageA(hwEdit, WM_CHAR, 22, 0);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+
+ /* get text */
+ buffer[0] = 0;
+ r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
+ ok(r == 0, "Expected: 0, got: %d\n", r);
+ ok(strcmp(buffer, "") == 0, "expected empty string, got %s\n", buffer);
+
+ DestroyWindow(hwEdit);
+}
+
+static void test_undo(void)
+{
+ HWND hwEdit;
+ LONG r;
+ DWORD cpMin, cpMax;
+ char buffer[1024];
+ const char* text = "undo this";
+
+ hwEdit = create_editcontrol(0, 0);
+ r = get_edit_style(hwEdit);
+ ok(0 == r, "Wrong style expected 0x%x got: 0x%x\n", 0, r);
+
+ /* set text */
+ r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) text);
+ ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r);
+
+ /* select all, */
+ cpMin = cpMax = 0xdeadbeef;
+ SendMessageA(hwEdit, EM_SETSEL, 0, -1);
+ r = SendMessageA(hwEdit, EM_GETSEL, (WPARAM) &cpMin, (LPARAM) &cpMax);
+ ok((strlen(text) << 16) == r, "Unexpected length %d\n", r);
+ ok(0 == cpMin, "Expected: %d, got %d\n", 0, cpMin);
+ ok(9 == cpMax, "Expected: %d, got %d\n", 9, cpMax);
+
+ /* cut (ctrl-x) */
+ r = SendMessageA(hwEdit, WM_CHAR, 24, 0);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+
+ /* get text */
+ buffer[0] = 0;
+ r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
+ ok(0 == r, "Expected: %d, got len %d\n", 0, r);
+ ok(0 == strcmp(buffer, ""), "expected %s, got %s\n", "", buffer);
+
+ /* undo (ctrl-z) */
+ r = SendMessageA(hwEdit, WM_CHAR, 26, 0);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+
+ /* get text */
+ buffer[0] = 0;
+ r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
+ ok(strlen(text) == r, "Unexpected length %d\n", r);
+ ok(0 == strcmp(buffer, text), "expected %s, got %s\n", text, buffer);
+
+ /* undo again (ctrl-z) */
+ r = SendMessageA(hwEdit, WM_CHAR, 26, 0);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+
+ /* get text */
+ buffer[0] = 0;
+ r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
+ ok(r == 0, "Expected: %d, got len %d\n", 0, r);
+ ok(0 == strcmp(buffer, ""), "expected %s, got %s\n", "", buffer);
+
+ DestroyWindow(hwEdit);
+}
+
+static void test_enter(void)
+{
+ char buffer[16];
+ HWND hwEdit;
+ LONG r;
+
+ /* multiline */
+ hwEdit = create_editcontrol(ES_MULTILINE, 0);
+ r = get_edit_style(hwEdit);
+ ok(ES_MULTILINE == r, "Wrong style expected ES_MULTILINE got: 0x%x\n", r);
+
+ /* set text */
+ r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) "");
+ ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r);
+
+ r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+
+ /* get text */
+ buffer[0] = 0;
+ r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer);
+ ok(2 == r, "Expected: %d, got len %d\n", 2, r);
+ ok(0 == strcmp(buffer, "\r\n"), "expected \"\\r\\n\", got \"%s\"\n", buffer);
+
+ DestroyWindow (hwEdit);
+
+ /* single line */
+ hwEdit = create_editcontrol(0, 0);
+ r = get_edit_style(hwEdit);
+ ok(0 == r, "Wrong style expected 0x%x got: 0x%x\n", 0, r);
+
+ /* set text */
+ r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) "");
+ ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r);
+
+ r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+
+ /* get text */
+ buffer[0] = 0;
+ r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer);
+ ok(0 == r, "Expected: %d, got len %d\n", 0, r);
+ ok(0 == strcmp(buffer, ""), "expected \"\", got \"%s\"\n", buffer);
+
+ DestroyWindow(hwEdit);
+
+ /* single line with ES_WANTRETURN */
+ hwEdit = create_editcontrol(ES_WANTRETURN, 0);
+ r = get_edit_style(hwEdit);
+ ok(ES_WANTRETURN == r, "Wrong style expected ES_WANTRETURN got: 0x%x\n", r);
+
+ /* set text */
+ r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) "");
+ ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r);
+
+ r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+
+ /* get text */
+ buffer[0] = 0;
+ r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer);
+ ok(0 == r, "Expected: %d, got len %d\n", 0, r);
+ ok(0 == strcmp(buffer, ""), "expected \"\", got \"%s\"\n", buffer);
+
+ DestroyWindow(hwEdit);
+}
+
+static void test_tab(void)
+{
+ char buffer[16];
+ HWND hwEdit;
+ LONG r;
+
+ /* multiline */
+ hwEdit = create_editcontrol(ES_MULTILINE, 0);
+ r = get_edit_style(hwEdit);
+ ok(ES_MULTILINE == r, "Wrong style expected ES_MULTILINE got: 0x%x\n", r);
+
+ /* set text */
+ r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) "");
+ ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r);
+
+ r = SendMessageA(hwEdit, WM_CHAR, VK_TAB, 0);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+
+ /* get text */
+ buffer[0] = 0;
+ r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer);
+ ok(1 == r, "Expected: %d, got len %d\n", 1, r);
+ ok(0 == strcmp(buffer, "\t"), "expected \"\\t\", got \"%s\"\n", buffer);
+
+ DestroyWindow(hwEdit);
+
+ /* single line */
+ hwEdit = create_editcontrol(0, 0);
+ r = get_edit_style(hwEdit);
+ ok(0 == r, "Wrong style expected 0x%x got: 0x%x\n", 0, r);
+
+ /* set text */
+ r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) "");
+ ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r);
+
+ r = SendMessageA(hwEdit, WM_CHAR, VK_TAB, 0);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+
+ /* get text */
+ buffer[0] = 0;
+ r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer);
+ ok(0 == r, "Expected: %d, got len %d\n", 0, r);
+ ok(0 == strcmp(buffer, ""), "expected \"\", got \"%s\"\n", buffer);
+
+ DestroyWindow(hwEdit);
+}
+
+static void test_edit_dialog(void)
+{
+ int r;
+
+ /* from bug 11841 */
+ r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 0);
+ ok(333 == r, "Expected %d, got %d\n", 333, r);
+ r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 1);
+ ok(111 == r, "Expected %d, got %d\n", 111, r);
+ r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 2);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+
+ /* more tests for WM_CHAR */
+ r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 3);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 4);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 5);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+
+ /* more tests for WM_KEYDOWN + WM_CHAR */
+ r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 6);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 7);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_READONLY_DIALOG", NULL, edit_dialog_proc, 8);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+
+ /* tests with an editable edit control */
+ r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 0);
+ ok(333 == r, "Expected %d, got %d\n", 333, r);
+ r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 1);
+ ok(111 == r, "Expected %d, got %d\n", 111, r);
+ r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 2);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+
+ /* tests for WM_CHAR */
+ r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 3);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 4);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 5);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+
+ /* tests for WM_KEYDOWN + WM_CHAR */
+ r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 6);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 7);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 8);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+
+ /* multiple tab tests */
+ r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 9);
+ ok(22 == r, "Expected %d, got %d\n", 22, r);
+ r = DialogBoxParamA(hinst, "EDIT_DIALOG", NULL, edit_dialog_proc, 10);
+ ok(33 == r, "Expected %d, got %d\n", 33, r);
+}
+
+static void test_multi_edit_dialog(void)
+{
+ int r;
+
+ /* test for multiple edit dialogs (bug 12319) */
+ r = DialogBoxParamA(hinst, "MULTI_EDIT_DIALOG", NULL, multi_edit_dialog_proc, 0);
+ ok(2222 == r, "Expected %d, got %d\n", 2222, r);
+ r = DialogBoxParamA(hinst, "MULTI_EDIT_DIALOG", NULL, multi_edit_dialog_proc, 1);
+ ok(1111 == r, "Expected %d, got %d\n", 1111, r);
+ r = DialogBoxParamA(hinst, "MULTI_EDIT_DIALOG", NULL, multi_edit_dialog_proc, 2);
+ ok(2222 == r, "Expected %d, got %d\n", 2222, r);
+ r = DialogBoxParamA(hinst, "MULTI_EDIT_DIALOG", NULL, multi_edit_dialog_proc, 3);
+ ok(11 == r, "Expected %d, got %d\n", 11, r);
+}
+
+static void test_wantreturn_edit_dialog(void)
+{
+ int r;
+
+ /* tests for WM_KEYDOWN */
+ r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 0);
+ ok(333 == r, "Expected %d, got %d\n", 333, r);
+ r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 1);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 2);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+
+ /* tests for WM_CHAR */
+ r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 3);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 4);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 5);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+
+ /* tests for WM_KEYDOWN + WM_CHAR */
+ r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 6);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 7);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_WANTRETURN_DIALOG", NULL, edit_wantreturn_dialog_proc, 8);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+}
+
+static void test_singleline_wantreturn_edit_dialog(void)
+{
+ int r;
+
+ /* tests for WM_KEYDOWN */
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 0);
+ ok(222 == r, "Expected %d, got %d\n", 222, r);
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 1);
+ ok(111 == r, "Expected %d, got %d\n", 111, r);
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 2);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+
+ /* tests for WM_CHAR */
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 3);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 4);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 5);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+
+ /* tests for WM_KEYDOWN + WM_CHAR */
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 6);
+ ok(222 == r, "Expected %d, got %d\n", 222, r);
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 7);
+ ok(111 == r, "Expected %d, got %d\n", 111, r);
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_DIALOG", NULL, edit_singleline_dialog_proc, 8);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+
+ /* tests for WM_KEYDOWN */
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 0);
+ ok(222 == r, "Expected %d, got %d\n", 222, r);
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 1);
+ ok(111 == r, "Expected %d, got %d\n", 111, r);
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 2);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+
+ /* tests for WM_CHAR */
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 3);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 4);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 5);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+
+ /* tests for WM_KEYDOWN + WM_CHAR */
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 6);
+ ok(222 == r, "Expected %d, got %d\n", 222, r);
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 7);
+ ok(111 == r, "Expected %d, got %d\n", 111, r);
+ r = DialogBoxParamA(hinst, "EDIT_SINGLELINE_WANTRETURN_DIALOG", NULL, edit_singleline_dialog_proc, 8);
+ ok(444 == r, "Expected %d, got %d\n", 444, r);
+}
+
+static int child_edit_wmkeydown_num_messages = 0;
+static INT_PTR CALLBACK child_edit_wmkeydown_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_DESTROY:
+ case WM_NCDESTROY:
+ break;
+
+ default:
+ child_edit_wmkeydown_num_messages++;
+ break;
+ }
+
+ return FALSE;
+}
+
+static void test_child_edit_wmkeydown(void)
+{
+ HWND hwEdit, hwParent;
+ int r;
+
+ hwEdit = create_child_editcontrol(0, 0);
+ hwParent = GetParent(hwEdit);
+ SetWindowLongPtrA(hwParent, GWLP_WNDPROC, (LONG_PTR)child_edit_wmkeydown_proc);
+ r = SendMessageA(hwEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ ok(0 == child_edit_wmkeydown_num_messages, "expected 0, got %d\n", child_edit_wmkeydown_num_messages);
+ destroy_child_editcontrol(hwEdit);
+}
+
+static BOOL got_en_setfocus = FALSE;
+static BOOL got_wm_capturechanged = FALSE;
+static LRESULT (CALLBACK *p_edit_proc)(HWND, UINT, WPARAM, LPARAM);
+
+static LRESULT CALLBACK edit4_wnd_procA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_COMMAND:
+ switch (HIWORD(wParam))
+ {
+ case EN_SETFOCUS:
+ got_en_setfocus = TRUE;
+ break;
+ }
+ break;
+ case WM_CAPTURECHANGED:
+ if (hWnd != (HWND)lParam)
+ {
+ got_wm_capturechanged = TRUE;
+ EndMenu();
+ }
+ break;
+ }
+ return DefWindowProcA(hWnd, msg, wParam, lParam);
+}
+
+struct context_menu_messages
+{
+ unsigned int wm_command, em_setsel;
+};
+
+static struct context_menu_messages menu_messages;
+
+static LRESULT CALLBACK child_edit_menu_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_ENTERIDLE:
+ if (wParam == MSGF_MENU)
+ {
+ HWND hwndMenu = (HWND)lParam;
+ MENUBARINFO mbi = { sizeof(mbi) };
+ if (GetMenuBarInfo(hwndMenu, OBJID_CLIENT, 0, &mbi))
+ {
+ MENUITEMINFOA mii = { sizeof(MENUITEMINFOA), MIIM_STATE };
+ if (GetMenuItemInfoA(mbi.hMenu, EM_SETSEL, FALSE, &mii))
+ {
+ if (mii.fState & MFS_HILITE)
+ {
+ PostMessageA(hwnd, WM_KEYDOWN, VK_RETURN, 0x1c0001);
+ PostMessageA(hwnd, WM_KEYUP, VK_RETURN, 0x1c0001);
+ }
+ else
+ {
+ PostMessageA(hwnd, WM_KEYDOWN, VK_DOWN, 0x500001);
+ PostMessageA(hwnd, WM_KEYUP, VK_DOWN, 0x500001);
+ }
+ }
+ }
+ }
+ break;
+ case WM_COMMAND:
+ menu_messages.wm_command++;
+ break;
+ case EM_SETSEL:
+ menu_messages.em_setsel++;
+ break;
+ }
+ return CallWindowProcA(p_edit_proc, hwnd, msg, wParam, lParam);
+}
+
+static void test_contextmenu(void)
+{
+ HWND hwndMain, hwndEdit;
+ MSG msg;
+
+ hwndMain = CreateWindowA(szEditTest4Class, "ET4", WS_OVERLAPPEDWINDOW|WS_VISIBLE,
+ 0, 0, 200, 200, NULL, NULL, hinst, NULL);
+ assert(hwndMain);
+
+ hwndEdit = CreateWindowA("EDIT", NULL,
+ WS_CHILD|WS_BORDER|WS_VISIBLE|ES_LEFT|ES_AUTOHSCROLL,
+ 0, 0, 150, 50, /* important this not be 0 size. */
+ hwndMain, (HMENU) ID_EDITTEST2, hinst, NULL);
+ assert(hwndEdit);
+
+ SetFocus(NULL);
+ SetCapture(hwndMain);
+ SendMessageA(hwndEdit, WM_CONTEXTMENU, (WPARAM)hwndEdit, MAKEWORD(10, 10));
+ ok(got_en_setfocus, "edit box didn't get focused\n");
+ ok(got_wm_capturechanged, "main window capture did not change\n");
+
+ DestroyWindow(hwndEdit);
+
+ hwndEdit = CreateWindowA("EDIT", "Test Text",
+ WS_CHILD | WS_BORDER | WS_VISIBLE,
+ 0, 0, 100, 100,
+ hwndMain, NULL, hinst, NULL);
+ memset(&menu_messages, 0, sizeof(menu_messages));
+ p_edit_proc = (void*)SetWindowLongPtrA(hwndEdit, GWLP_WNDPROC,
+ (ULONG_PTR)child_edit_menu_proc);
+
+ SetFocus(hwndEdit);
+ SendMessageA(hwndEdit, WM_SETTEXT, 0, (LPARAM)"foo");
+ SendMessageA(hwndEdit, WM_CONTEXTMENU, (WPARAM)hwndEdit, MAKEWORD(-1, -1));
+ while (PeekMessageA(&msg, hwndEdit, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+ ok(menu_messages.wm_command == 0,
+ "Expected no WM_COMMAND messages, got %d\n", menu_messages.wm_command);
+ ok(menu_messages.em_setsel == 1,
+ "Expected 1 EM_SETSEL message, got %d\n", menu_messages.em_setsel);
+
+ DestroyWindow(hwndEdit);
+ DestroyWindow(hwndMain);
+}
+
+static BOOL register_classes(void)
+{
+ WNDCLASSA test2;
+ WNDCLASSA test3;
+ WNDCLASSA test4;
+ WNDCLASSA text_position;
+
+ test2.style = 0;
+ test2.lpfnWndProc = ET2_WndProc;
+ test2.cbClsExtra = 0;
+ test2.cbWndExtra = 0;
+ test2.hInstance = hinst;
+ test2.hIcon = NULL;
+ test2.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
+ test2.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ test2.lpszMenuName = NULL;
+ test2.lpszClassName = szEditTest2Class;
+ if (!RegisterClassA(&test2)) return FALSE;
+
+ test3.style = 0;
+ test3.lpfnWndProc = edit3_wnd_procA;
+ test3.cbClsExtra = 0;
+ test3.cbWndExtra = 0;
+ test3.hInstance = hinst;
+ test3.hIcon = 0;
+ test3.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
+ test3.hbrBackground = GetStockObject(WHITE_BRUSH);
+ test3.lpszMenuName = NULL;
+ test3.lpszClassName = szEditTest3Class;
+ if (!RegisterClassA(&test3)) return FALSE;
+
+ test4.style = 0;
+ test4.lpfnWndProc = edit4_wnd_procA;
+ test4.cbClsExtra = 0;
+ test4.cbWndExtra = 0;
+ test4.hInstance = hinst;
+ test4.hIcon = NULL;
+ test4.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
+ test4.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ test4.lpszMenuName = NULL;
+ test4.lpszClassName = szEditTest4Class;
+ if (!RegisterClassA(&test4)) return FALSE;
+
+ text_position.style = CS_HREDRAW | CS_VREDRAW;
+ text_position.cbClsExtra = 0;
+ text_position.cbWndExtra = 0;
+ text_position.hInstance = hinst;
+ text_position.hIcon = NULL;
+ text_position.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
+ text_position.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
+ text_position.lpszMenuName = NULL;
+ text_position.lpszClassName = szEditTextPositionClass;
+ text_position.lpfnWndProc = DefWindowProcA;
+ if (!RegisterClassA(&text_position)) return FALSE;
+
+ return TRUE;
+}
+
+static void UnregisterWindowClasses (void)
+{
+ UnregisterClassA(szEditTest2Class, hinst);
+ UnregisterClassA(szEditTest3Class, hinst);
+ UnregisterClassA(szEditTest4Class, hinst);
+ UnregisterClassA(szEditTextPositionClass, hinst);
+}
+
+static void test_fontsize(void)
+{
+ HWND hwEdit;
+ HFONT hfont;
+ HDC hDC;
+ LOGFONTA lf;
+ LONG r;
+ char szLocalString[MAXLEN];
+ int dpi;
+
+ hDC = GetDC(NULL);
+ dpi = GetDeviceCaps(hDC, LOGPIXELSY);
+ ReleaseDC(NULL, hDC);
+
+ memset(&lf,0,sizeof(LOGFONTA));
+ strcpy(lf.lfFaceName,"Arial");
+ lf.lfHeight = -300; /* taller than the edit box */
+ lf.lfWeight = 500;
+ hfont = CreateFontIndirectA(&lf);
+
+ trace("EDIT: Oversized font (Multi line)\n");
+ hwEdit= CreateWindowA("EDIT", NULL, ES_MULTILINE|ES_AUTOHSCROLL,
+ 0, 0, (150 * dpi) / 96, (50 * dpi) / 96, NULL, NULL,
+ hinst, NULL);
+
+ SendMessageA(hwEdit,WM_SETFONT,(WPARAM)hfont,0);
+
+ if (winetest_interactive)
+ ShowWindow (hwEdit, SW_SHOW);
+
+ r = SendMessageA(hwEdit, WM_CHAR, 'A', 1);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+ r = SendMessageA(hwEdit, WM_CHAR, 'B', 1);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+ r = SendMessageA(hwEdit, WM_CHAR, 'C', 1);
+ ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+
+ GetWindowTextA(hwEdit, szLocalString, MAXLEN);
+ ok(strcmp(szLocalString, "ABC")==0,
+ "Wrong contents of edit: %s\n", szLocalString);
+
+ r = SendMessageA(hwEdit, EM_POSFROMCHAR,0,0);
+ ok(r != -1,"EM_POSFROMCHAR failed index 0\n");
+ r = SendMessageA(hwEdit, EM_POSFROMCHAR,1,0);
+ ok(r != -1,"EM_POSFROMCHAR failed index 1\n");
+ r = SendMessageA(hwEdit, EM_POSFROMCHAR,2,0);
+ ok(r != -1,"EM_POSFROMCHAR failed index 2\n");
+ r = SendMessageA(hwEdit, EM_POSFROMCHAR,3,0);
+ ok(r == -1,"EM_POSFROMCHAR succeeded index 3\n");
+
+ DestroyWindow (hwEdit);
+ DeleteObject(hfont);
+}
+
+struct dialog_mode_messages
+{
+ int wm_getdefid, wm_close, wm_command, wm_nextdlgctl;
+};
+
+static struct dialog_mode_messages dm_messages;
+
+static void zero_dm_messages(void)
+{
+ dm_messages.wm_command = 0;
+ dm_messages.wm_close = 0;
+ dm_messages.wm_getdefid = 0;
+ dm_messages.wm_nextdlgctl = 0;
+}
+
+#define test_dm_messages(wmcommand, wmclose, wmgetdefid, wmnextdlgctl) \
+ ok(dm_messages.wm_command == wmcommand, "expected %d WM_COMMAND messages, " \
+ "got %d\n", wmcommand, dm_messages.wm_command); \
+ ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE messages, " \
+ "got %d\n", wmclose, dm_messages.wm_close); \
+ ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID messages, " \
+ "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\
+ ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL messages, " \
+ "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl)
+
+static LRESULT CALLBACK dialog_mode_wnd_proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (iMsg)
+ {
+ case WM_COMMAND:
+ dm_messages.wm_command++;
+ break;
+ case DM_GETDEFID:
+ dm_messages.wm_getdefid++;
+ return MAKELONG(ID_EDITTESTDBUTTON, DC_HASDEFID);
+ case WM_NEXTDLGCTL:
+ dm_messages.wm_nextdlgctl++;
+ break;
+ case WM_CLOSE:
+ dm_messages.wm_close++;
+ break;
+ }
+
+ return DefWindowProcA(hwnd, iMsg, wParam, lParam);
+}
+
+static void test_dialogmode(void)
+{
+ HWND hwEdit, hwParent, hwButton;
+ MSG msg= {0};
+ int len, r;
+ hwEdit = create_child_editcontrol(ES_MULTILINE, 0);
+
+ r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0);
+ ok(11 == len, "expected 11, got %d\n", len);
+
+ r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, 0);
+ ok(0x8d == r, "expected 0x8d, got 0x%x\n", r);
+
+ r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0);
+ ok(13 == len, "expected 13, got %d\n", len);
+
+ r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
+ ok(0x8d == r, "expected 0x8d, got 0x%x\n", r);
+ r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0);
+ ok(13 == len, "expected 13, got %d\n", len);
+
+ r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0);
+ ok(13 == len, "expected 13, got %d\n", len);
+
+ destroy_child_editcontrol(hwEdit);
+
+ hwEdit = create_editcontrol(ES_MULTILINE, 0);
+
+ r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0);
+ ok(11 == len, "expected 11, got %d\n", len);
+
+ msg.hwnd = hwEdit;
+ msg.message = WM_KEYDOWN;
+ msg.wParam = VK_BACK;
+ msg.lParam = 0xe0001;
+ r = SendMessageA(hwEdit, WM_GETDLGCODE, VK_BACK, (LPARAM)&msg);
+ ok(0x8d == r, "expected 0x8d, got 0x%x\n", r);
+
+ r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ len = SendMessageA(hwEdit, WM_GETTEXTLENGTH, 0, 0);
+ ok(11 == len, "expected 11, got %d\n", len);
+
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_child_editcontrol(0, 0);
+ hwParent = GetParent(hwEdit);
+ SetWindowLongPtrA(hwParent, GWLP_WNDPROC, (LONG_PTR)dialog_mode_wnd_proc);
+
+ zero_dm_messages();
+ r = SendMessageA(hwEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ test_dm_messages(0, 0, 0, 0);
+ zero_dm_messages();
+
+ r = SendMessageA(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ test_dm_messages(0, 0, 0, 0);
+ zero_dm_messages();
+
+ msg.hwnd = hwEdit;
+ msg.message = WM_KEYDOWN;
+ msg.wParam = VK_TAB;
+ msg.lParam = 0xf0001;
+ r = SendMessageA(hwEdit, WM_GETDLGCODE, VK_TAB, (LPARAM)&msg);
+ ok(0x89 == r, "expected 0x89, got 0x%x\n", r);
+ test_dm_messages(0, 0, 0, 0);
+ zero_dm_messages();
+
+ r = SendMessageA(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ test_dm_messages(0, 0, 0, 0);
+ zero_dm_messages();
+
+ destroy_child_editcontrol(hwEdit);
+
+ hwEdit = create_child_editcontrol(ES_MULTILINE, 0);
+ hwParent = GetParent(hwEdit);
+ SetWindowLongPtrA(hwParent, GWLP_WNDPROC, (LONG_PTR)dialog_mode_wnd_proc);
+
+ r = SendMessageA(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ test_dm_messages(0, 0, 0, 0);
+ zero_dm_messages();
+
+ msg.hwnd = hwEdit;
+ msg.message = WM_KEYDOWN;
+ msg.wParam = VK_ESCAPE;
+ msg.lParam = 0x10001;
+ r = SendMessageA(hwEdit, WM_GETDLGCODE, VK_ESCAPE, (LPARAM)&msg);
+ ok(0x8d == r, "expected 0x8d, got 0x%x\n", r);
+ test_dm_messages(0, 0, 0, 0);
+ zero_dm_messages();
+
+ r = SendMessageA(hwEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ test_dm_messages(0, 0, 0, 0);
+ zero_dm_messages();
+
+ r = SendMessageA(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ test_dm_messages(0, 0, 0, 1);
+ zero_dm_messages();
+
+ r = SendMessageA(hwEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ test_dm_messages(0, 0, 1, 0);
+ zero_dm_messages();
+
+ hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON,
+ 100, 100, 50, 20, hwParent, (HMENU)ID_EDITTESTDBUTTON, hinst, NULL);
+ ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError());
+
+ r = SendMessageA(hwEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
+ ok(1 == r, "expected 1, got %d\n", r);
+ test_dm_messages(0, 0, 1, 1);
+ zero_dm_messages();
+
+ DestroyWindow(hwButton);
+ destroy_child_editcontrol(hwEdit);
+}
+
+static void test_EM_GETHANDLE(void)
+{
+ static const WCHAR str1W[] = {'1','1','1','1','+','1','1','1','1','+','1','1','1','1','#',0};
+ static const WCHAR str2W[] = {'2','2','2','2','-','2','2','2','2','-','2','2','2','2','-','2','2','2','2','#',0};
+ static const char str0[] = "untouched";
+ static const char str1[] = "1111+1111+1111#";
+ static const char str1_1[] = "2111+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;
+ WCHAR *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) SendMessageA(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) SendMessageA(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 = lstrlenW(buffer);
+todo_wine
+ ok(len == lstrlenW(str1W) && !lstrcmpW(buffer, str1W), "Unexpected buffer contents %s, length %d.\n",
+ wine_dbgstr_w(buffer), len);
+ LocalUnlock(hmem);
+
+ /* See if WM_GETTEXTLENGTH/WM_GETTEXT still work. */
+ len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0);
+ ok(len == lstrlenA(str1), "Unexpected text length %d.\n", len);
+
+ lstrcpyA(current, str0);
+ r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current);
+ ok((r == lstrlenA(str1)) && !lstrcmpA(current, str1),
+ "Unexpected retval %d and text \"%s\" (expected %d and \"%s\")\n", r, current, lstrlenA(str1), str1);
+
+ /* Application altered buffer contents, see if WM_GETTEXTLENGTH/WM_GETTEXT pick that up. */
+ buffer = LocalLock(hmem);
+ ok(buffer != NULL, "got %p (expected != NULL)\n", buffer);
+ buffer[0] = '2';
+ LocalUnlock(hmem);
+
+ len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0);
+ ok(len == lstrlenA(str1_1), "Unexpected text length %d.\n", len);
+
+ lstrcpyA(current, str0);
+ r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current);
+todo_wine
+ ok(r == lstrlenA(str1_1) && !lstrcmpA(current, str1_1),
+ "Unexpected retval %d and text \"%s\" (expected %d and \"%s\")\n", r, current, lstrlenA(str1_1), str1_1);
+
+ /* See if WM_SETTEXT/EM_REPLACESEL work. */
+ r = SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)str1);
+ ok(r, "Failed to set text.\n");
+
+ buffer = LocalLock(hmem);
+todo_wine
+ ok(buffer != NULL && buffer[0] == '1', "Unexpected buffer contents\n");
+ LocalUnlock(hmem);
+
+ r = SendMessageA(hEdit, EM_REPLACESEL, 0, (LPARAM)str1_1);
+ ok(r, "Failed to replace selection.\n");
+
+ buffer = LocalLock(hmem);
+todo_wine
+ ok(buffer != NULL && buffer[0] == '2', "Unexpected buffer contents\n");
+ 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);
+ lstrcpyW(buffer, str2W);
+ 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);
+
+ SendMessageA(hEdit, EM_SETHANDLE, (WPARAM)halloc, 0);
+
+ len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0);
+todo_wine
+ ok(len == lstrlenA(str2), "got %d (expected %d)\n", len, lstrlenA(str2));
+
+ lstrcpyA(current, str0);
+ r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current);
+todo_wine
+ 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 up to EM_GETHANDLE */
+ hmem = (HGLOBAL) SendMessageA(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) SendMessageA(hEdit, EM_GETHANDLE, 0, 0);
+ ok(hmem2 == hmem, "got %p (expected %p)\n", hmem2, hmem);
+
+ /* Let the edit control free the memory handle */
+ SendMessageA(hEdit, EM_SETHANDLE, (WPARAM)hmem2, 0);
+
+ DestroyWindow(hEdit);
+}
+
+static void test_paste(void)
+{
+ static const char *str = "this is a simple text";
+ static const char *str2 = "first line\r\nsecond line";
+ HWND hEdit, hMultilineEdit;
+ HANDLE hmem, hmem_ret;
+ char *buffer;
+ int r, len;
+
+ hEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
+ hMultilineEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE, 0);
+
+ /* Prepare clipboard data with simple text */
+ hmem = GlobalAlloc(GMEM_MOVEABLE, 255);
+ ok(hmem != NULL, "got %p (expected != NULL)\n", hmem);
+ buffer = GlobalLock(hmem);
+ ok(buffer != NULL, "got %p (expected != NULL)\n", buffer);
+ strcpy(buffer, str);
+ GlobalUnlock(hmem);
+
+ r = OpenClipboard(hEdit);
+ ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
+ r = EmptyClipboard();
+ ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
+ hmem_ret = SetClipboardData(CF_TEXT, hmem);
+ ok(hmem_ret == hmem, "expected %p, got %p\n", hmem, hmem_ret);
+ r = CloseClipboard();
+ ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
+
+ /* Paste single line */
+ SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)"");
+ r = SendMessageA(hEdit, WM_PASTE, 0, 0);
+ len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0);
+ ok(strlen(str) == len, "got %d\n", len);
+
+ /* Prepare clipboard data with multiline text */
+ hmem = GlobalAlloc(GMEM_MOVEABLE, 255);
+ ok(hmem != NULL, "got %p (expected != NULL)\n", hmem);
+ buffer = GlobalLock(hmem);
+ ok(buffer != NULL, "got %p (expected != NULL)\n", buffer);
+ strcpy(buffer, str2);
+ GlobalUnlock(hmem);
+
+ r = OpenClipboard(hEdit);
+ ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
+ r = EmptyClipboard();
+ ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
+ hmem_ret = SetClipboardData(CF_TEXT, hmem);
+ ok(hmem_ret == hmem, "expected %p, got %p\n", hmem, hmem_ret);
+ r = CloseClipboard();
+ ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
+
+ /* Paste multiline text in singleline edit - should be cut */
+ SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)"");
+ r = SendMessageA(hEdit, WM_PASTE, 0, 0);
+ len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0);
+ ok(strlen("first line") == len, "got %d\n", len);
+
+ /* Paste multiline text in multiline edit */
+ SendMessageA(hMultilineEdit, WM_SETTEXT, 0, (LPARAM)"");
+ r = SendMessageA(hMultilineEdit, WM_PASTE, 0, 0);
+ len = SendMessageA(hMultilineEdit, WM_GETTEXTLENGTH, 0, 0);
+ ok(strlen(str2) == len, "got %d\n", len);
+
+ /* Cleanup */
+ DestroyWindow(hEdit);
+ DestroyWindow(hMultilineEdit);
+}
+
+static void test_EM_GETLINE(void)
+{
+ HWND hwnd[2];
+ int i;
+
+ 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++)
+ {
+ static const WCHAR strW[] = {'t','e','x','t',0};
+ static const char *str = "text";
+ WCHAR buffW[16];
+ char buff[16];
+ int r;
+
+ todo_wine_if(i == 0)
+ ok(IsWindowUnicode(hwnd[i]), "Expected unicode window.\n");
+
+ SendMessageA(hwnd[i], WM_SETTEXT, 0, (LPARAM)str);
+
+ memset(buff, 0, sizeof(buff));
+ *(WORD *)buff = sizeof(buff);
+ r = SendMessageA(hwnd[i], EM_GETLINE, 0, (LPARAM)buff);
+ ok(r == strlen(str), "Failed to get a line %d.\n", r);
+ ok(!strcmp(buff, str), "Unexpected line data %s.\n", buff);
+
+ memset(buff, 0, sizeof(buff));
+ *(WORD *)buff = sizeof(buff);
+ r = SendMessageA(hwnd[i], EM_GETLINE, 1, (LPARAM)buff);
+ ok(r == strlen(str), "Failed to get a line %d.\n", r);
+ ok(!strcmp(buff, str), "Unexpected line data %s.\n", buff);
+
+ memset(buffW, 0, sizeof(buffW));
+ *(WORD *)buffW = sizeof(buffW)/sizeof(buffW[0]);
+ 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]);
+ 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));
+
+ DestroyWindow(hwnd[i]);
+ }
+}
+
+START_TEST(edit)
+{
+ ULONG_PTR ctx_cookie;
+ HANDLE hCtx;
+ BOOL b;
+
+ if (!load_v6_module(&ctx_cookie, &hCtx))
+ return;
+
+ hinst = GetModuleHandleA(NULL);
+ b = register_classes();
+ ok(b, "Failed to register test classes.\n");
+ if (!b) return;
+
+ test_edit_control_1();
+ test_edit_control_2();
+ test_edit_control_3();
+ test_char_from_pos();
+ test_edit_control_5();
+ test_edit_control_6();
+ test_edit_control_limittext();
+ test_edit_control_scroll();
+ test_margins();
+ test_margins_font_change();
+ test_text_position();
+ test_espassword();
+ test_undo();
+ test_enter();
+ test_tab();
+ test_edit_dialog();
+ test_multi_edit_dialog();
+ test_wantreturn_edit_dialog();
+ test_singleline_wantreturn_edit_dialog();
+ test_child_edit_wmkeydown();
+ test_fontsize();
+ test_dialogmode();
+ test_contextmenu();
+ test_EM_GETHANDLE();
+ test_paste();
+ test_EM_GETLINE();
+
+ UnregisterWindowClasses();
+
+ unload_v6_module(ctx_cookie, hCtx);
+}
#include "poppack.h"
static HIMAGELIST (WINAPI *pImageList_Create)(int, int, UINT, int, int);
+static BOOL (WINAPI *pImageList_Destroy)(HIMAGELIST);
static int (WINAPI *pImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP);
static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*);
static BOOL (WINAPI *pImageList_SetImageCount)(HIMAGELIST,UINT);
REFIID,void **);
static HRESULT (WINAPI *pHIMAGELIST_QueryInterface)(HIMAGELIST,REFIID,void **);
static int (WINAPI *pImageList_SetColorTable)(HIMAGELIST,int,int,RGBQUAD*);
+static DWORD (WINAPI *pImageList_GetFlags)(HIMAGELIST);
+static BOOL (WINAPI *pImageList_BeginDrag)(HIMAGELIST, int, int, int);
+static HIMAGELIST (WINAPI *pImageList_GetDragImage)(POINT *, POINT *);
+static void (WINAPI *pImageList_EndDrag)(void);
+static INT (WINAPI *pImageList_GetImageCount)(HIMAGELIST);
+static BOOL (WINAPI *pImageList_SetDragCursorImage)(HIMAGELIST, int, int, int);
+static BOOL (WINAPI *pImageList_GetIconSize)(HIMAGELIST, int *, int *);
+static BOOL (WINAPI *pImageList_Remove)(HIMAGELIST, int);
+static INT (WINAPI *pImageList_ReplaceIcon)(HIMAGELIST, int, HICON);
+static BOOL (WINAPI *pImageList_Replace)(HIMAGELIST, int, HBITMAP, HBITMAP);
+static HIMAGELIST (WINAPI *pImageList_Merge)(HIMAGELIST, int, HIMAGELIST, int, int, int);
+static BOOL (WINAPI *pImageList_GetImageInfo)(HIMAGELIST, int, IMAGEINFO *);
+static BOOL (WINAPI *pImageList_Write)(HIMAGELIST, IStream *);
+static HIMAGELIST (WINAPI *pImageList_Read)(IStream *);
+static BOOL (WINAPI *pImageList_Copy)(HIMAGELIST, int, HIMAGELIST, int, UINT);
+static HIMAGELIST (WINAPI *pImageList_LoadImageW)(HINSTANCE, LPCWSTR, int, int, COLORREF, UINT, UINT);
static HINSTANCE hinst;
Sleep(1000);
}
+static BOOL is_v6_test(void)
+{
+ return pHIMAGELIST_QueryInterface != NULL;
+}
+
/* These macros build cursor/bitmap data in 4x4 pixel blocks */
#define B(x,y) ((x?0xf0:0)|(y?0xf:0))
#define ROW1(a,b,c,d,e,f,g,h) B(a,b),B(c,d),B(e,f),B(g,h)
static HIMAGELIST createImageList(int cx, int cy)
{
/* Create an ImageList and put an image into it */
- HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR, 1, 1);
+ HIMAGELIST himl = pImageList_Create(cx, cy, ILC_COLOR, 1, 1);
HBITMAP hbm = CreateBitmap(48, 48, 1, 1, bitmap_bits);
- ImageList_Add(himl, hbm, NULL);
+
+ ok(himl != NULL, "Failed to create image list, %d x %d.\n", cx, cy);
+ pImageList_Add(himl, hbm, NULL);
DeleteObject(hbm);
return himl;
}
-static HWND create_a_window(void)
+static HWND create_window(void)
{
char className[] = "bmwnd";
char winName[] = "Test Bitmap";
int count;
POINT hotspot;
- count = ImageList_GetImageCount(himl);
+ count = pImageList_GetImageCount(himl);
ok(count > 2, "Tests need an ImageList with more than 2 images\n");
/* Two BeginDrag() without EndDrag() in between */
- ret = ImageList_BeginDrag(himl, 1, 0, 0);
- drag = ImageList_GetDragImage(NULL, NULL);
+ ret = pImageList_BeginDrag(himl, 1, 0, 0);
+ drag = pImageList_GetDragImage(NULL, NULL);
ok(ret && drag, "ImageList_BeginDrag() failed\n");
- ret = ImageList_BeginDrag(himl, 0, 3, 5);
+ ret = pImageList_BeginDrag(himl, 0, 3, 5);
ok(!ret, "ImageList_BeginDrag() returned TRUE\n");
- drag = ImageList_GetDragImage(NULL, &hotspot);
+ drag = pImageList_GetDragImage(NULL, &hotspot);
ok(!!drag, "No active ImageList drag left\n");
ok(hotspot.x == 0 && hotspot.y == 0, "New ImageList drag was created\n");
- ImageList_EndDrag();
- drag = ImageList_GetDragImage(NULL, NULL);
+ pImageList_EndDrag();
+ drag = pImageList_GetDragImage(NULL, NULL);
ok(!drag, "ImageList drag was not destroyed\n");
/* Invalid image index */
- ImageList_BeginDrag(himl, 0, 0, 0);
- ret = ImageList_BeginDrag(himl, count, 3, 5);
+ pImageList_BeginDrag(himl, 0, 0, 0);
+ ret = pImageList_BeginDrag(himl, count, 3, 5);
ok(!ret, "ImageList_BeginDrag() returned TRUE\n");
- drag = ImageList_GetDragImage(NULL, &hotspot);
+ drag = pImageList_GetDragImage(NULL, &hotspot);
ok(drag && hotspot.x == 0 && hotspot.y == 0, "Active drag should not have been canceled\n");
- ImageList_EndDrag();
- drag = ImageList_GetDragImage(NULL, NULL);
+ pImageList_EndDrag();
+ drag = pImageList_GetDragImage(NULL, NULL);
ok(!drag, "ImageList drag was not destroyed\n");
/* Invalid negative image indexes succeed */
- ret = ImageList_BeginDrag(himl, -17, 0, 0);
- drag = ImageList_GetDragImage(NULL, NULL);
+ ret = pImageList_BeginDrag(himl, -17, 0, 0);
+ drag = pImageList_GetDragImage(NULL, NULL);
ok(ret && drag, "ImageList drag was created\n");
- ImageList_EndDrag();
- ret = ImageList_BeginDrag(himl, -1, 0, 0);
- drag = ImageList_GetDragImage(NULL, NULL);
+ pImageList_EndDrag();
+ ret = pImageList_BeginDrag(himl, -1, 0, 0);
+ drag = pImageList_GetDragImage(NULL, NULL);
ok(ret && drag, "ImageList drag was created\n");
- ImageList_EndDrag();
- ImageList_Destroy(himl);
+ pImageList_EndDrag();
+ pImageList_Destroy(himl);
}
static void test_hotspot(void)
int i, j, ret;
HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1);
HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2);
- HWND hwnd = create_a_window();
+ HWND hwnd = create_window();
for (i = 0; i < HOTSPOTS_MAX; i++) {
HIMAGELIST himlNew;
POINT ppt;
- ret = ImageList_BeginDrag(himl1, 0, dx1, dy1);
+ ret = pImageList_BeginDrag(himl1, 0, dx1, dy1);
ok(ret != 0, "BeginDrag failed for { %d, %d }\n", dx1, dy1);
sprintf(loc, "BeginDrag (%d,%d)\n", i, j);
show_image(hwnd, himl1, 0, max(SIZEX1, SIZEY1), loc, TRUE);
/* check merging the dragged image with a second image */
- ret = ImageList_SetDragCursorImage(himl2, 0, dx2, dy2);
+ ret = pImageList_SetDragCursorImage(himl2, 0, dx2, dy2);
ok(ret != 0, "SetDragCursorImage failed for {%d, %d}{%d, %d}\n",
dx1, dy1, dx2, dy2);
sprintf(loc, "SetDragCursorImage (%d,%d)\n", i, j);
show_image(hwnd, himl2, 0, max(SIZEX2, SIZEY2), loc, TRUE);
/* check new hotspot, it should be the same like the old one */
- himlNew = ImageList_GetDragImage(NULL, &ppt);
+ himlNew = pImageList_GetDragImage(NULL, &ppt);
ok(ppt.x == dx1 && ppt.y == dy1,
"Expected drag hotspot [%d,%d] got [%d,%d]\n",
dx1, dy1, ppt.x, ppt.y);
/* check size of new dragged image */
- ImageList_GetIconSize(himlNew, &newx, &newy);
+ pImageList_GetIconSize(himlNew, &newx, &newy);
correctx = max(SIZEX1, max(SIZEX2 + dx2, SIZEX1 - dx2));
correcty = max(SIZEY1, max(SIZEY2 + dy2, SIZEY1 - dy2));
ok(newx == correctx && newy == correcty,
correctx, correcty, newx, newy);
sprintf(loc, "GetDragImage (%d,%d)\n", i, j);
show_image(hwnd, himlNew, 0, max(correctx, correcty), loc, TRUE);
- ImageList_EndDrag();
+ pImageList_EndDrag();
}
}
#undef SIZEX1
#undef SIZEX2
#undef SIZEY2
#undef HOTSPOTS_MAX
- ImageList_Destroy(himl2);
- ImageList_Destroy(himl1);
+ pImageList_Destroy(himl2);
+ pImageList_Destroy(himl1);
DestroyWindow(hwnd);
}
HICON hicon3 ;
/* create an imagelist to play with */
- himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
+ himl = pImageList_Create(84, 84, ILC_COLOR16, 0, 3);
ok(himl!=0,"failed to create imagelist\n");
/* load the icons to add to the image list */
ok(hicon3 != 0, "no hicon3\n");
/* remove when nothing exists */
- ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
+ ok(!pImageList_Remove(himl, 0), "Removed nonexistent icon.\n");
/* removing everything from an empty imagelist should succeed */
- ok(ImageList_RemoveAll(himl),"removed nonexistent icon\n");
+ ok(pImageList_Remove(himl, -1), "Removed nonexistent icon\n");
/* add three */
- ok(0==ImageList_AddIcon(himl, hicon1),"failed to add icon1\n");
- ok(1==ImageList_AddIcon(himl, hicon2),"failed to add icon2\n");
- ok(2==ImageList_AddIcon(himl, hicon3),"failed to add icon3\n");
+ ok(0 == pImageList_ReplaceIcon(himl, -1, hicon1), "Failed to add icon1.\n");
+ ok(1 == pImageList_ReplaceIcon(himl, -1, hicon2), "Failed to add icon2.\n");
+ ok(2 == pImageList_ReplaceIcon(himl, -1, hicon3), "Failed to add icon3.\n");
/* remove an index out of range */
- ok(!ImageList_Remove(himl,4711),"removed nonexistent icon\n");
+ ok(!pImageList_Remove(himl, 4711), "removed nonexistent icon\n");
/* remove three */
- ok(ImageList_Remove(himl,0),"can't remove 0\n");
- ok(ImageList_Remove(himl,0),"can't remove 0\n");
- ok(ImageList_Remove(himl,0),"can't remove 0\n");
+ ok(pImageList_Remove(himl, 0), "Can't remove 0\n");
+ ok(pImageList_Remove(himl, 0), "Can't remove 0\n");
+ ok(pImageList_Remove(himl, 0), "Can't remove 0\n");
/* remove one extra */
- ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
+ ok(!pImageList_Remove(himl, 0), "Removed nonexistent icon.\n");
/* destroy it */
- ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
+ ok(pImageList_Destroy(himl), "Failed to destroy imagelist.\n");
- ok(-1==ImageList_AddIcon((HIMAGELIST)0xdeadbeef, hicon1),"don't crash on bad handle\n");
+ ok(-1 == pImageList_ReplaceIcon((HIMAGELIST)0xdeadbeef, -1, hicon1), "Don't crash on bad handle\n");
- ok(DestroyIcon(hicon1),"icon 1 wasn't deleted\n");
- ok(DestroyIcon(hicon2),"icon 2 wasn't deleted\n");
- ok(DestroyIcon(hicon3),"icon 3 wasn't deleted\n");
+ ok(DestroyIcon(hicon1), "Failed to destroy icon 1.\n");
+ ok(DestroyIcon(hicon2), "Failed to destroy icon 2.\n");
+ ok(DestroyIcon(hicon3), "Failed to destroy icon 3.\n");
}
static void test_imagecount(void)
{
HIMAGELIST himl;
- ok(0==ImageList_GetImageCount((HIMAGELIST)0xdeadbeef),"don't crash on bad handle\n");
+ ok(0 == pImageList_GetImageCount((HIMAGELIST)0xdeadbeef), "don't crash on bad handle\n");
if (!pImageList_SetImageCount)
{
return;
}
- himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
- ok(himl!=0,"failed to create imagelist\n");
+ himl = pImageList_Create(84, 84, ILC_COLOR16, 0, 3);
+ ok(himl != 0, "Failed to create imagelist.\n");
ok(pImageList_SetImageCount(himl, 3), "couldn't increase image count\n");
- ok(ImageList_GetImageCount(himl) == 3, "invalid image count after increase\n");
+ ok(pImageList_GetImageCount(himl) == 3, "invalid image count after increase\n");
ok(pImageList_SetImageCount(himl, 1), "couldn't decrease image count\n");
- ok(ImageList_GetImageCount(himl) == 1, "invalid image count after decrease to 1\n");
+ ok(pImageList_GetImageCount(himl) == 1, "invalid image count after decrease to 1\n");
ok(pImageList_SetImageCount(himl, 0), "couldn't decrease image count\n");
- ok(ImageList_GetImageCount(himl) == 0, "invalid image count after decrease to 0\n");
+ ok(pImageList_GetImageCount(himl) == 0, "invalid image count after decrease to 0\n");
- ok(ImageList_Destroy(himl), "destroy imagelist failed\n");
+ ok(pImageList_Destroy(himl), "Failed to destroy imagelist.\n");
}
static void test_DrawIndirect(void)
return;
}
- hwndfortest = create_a_window();
+ hwndfortest = create_window();
hdc = GetDC(hwndfortest);
ok(hdc!=NULL, "couldn't get DC\n");
/* create an imagelist to play with */
- himl = ImageList_Create(48, 48, ILC_COLOR16, 0, 3);
- ok(himl!=0,"failed to create imagelist\n");
+ himl = pImageList_Create(48, 48, ILC_COLOR16, 0, 3);
+ ok(himl != 0, "Failed to create imagelist.\n");
/* load the icons to add to the image list */
hbm1 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
ok(hbm3 != 0, "no bitmap 3\n");
/* add three */
- ok(0==ImageList_Add(himl, hbm1, 0),"failed to add bitmap 1\n");
- ok(1==ImageList_Add(himl, hbm2, 0),"failed to add bitmap 2\n");
+ ok(0 == ImageList_Add(himl, hbm1, 0),"failed to add bitmap 1\n");
+ ok(1 == ImageList_Add(himl, hbm2, 0),"failed to add bitmap 2\n");
if (pImageList_SetImageCount)
{
ok(pImageList_SetImageCount(himl,3),"Setimage count failed\n");
/*ok(2==ImageList_Add(himl, hbm3, NULL),"failed to add bitmap 3\n"); */
- ok(ImageList_Replace(himl, 2, hbm3, 0),"failed to replace bitmap 3\n");
+ ok(pImageList_Replace(himl, 2, hbm3, 0),"failed to replace bitmap 3\n");
}
memset(&imldp, 0, sizeof (imldp));
ok(!pImageList_DrawIndirect(&imldp),"should fail\n");
/* remove three */
- ok(ImageList_Remove(himl, 0), "removing 1st bitmap\n");
- ok(ImageList_Remove(himl, 0), "removing 2nd bitmap\n");
- ok(ImageList_Remove(himl, 0), "removing 3rd bitmap\n");
+ ok(pImageList_Remove(himl, 0), "removing 1st bitmap\n");
+ ok(pImageList_Remove(himl, 0), "removing 2nd bitmap\n");
+ ok(pImageList_Remove(himl, 0), "removing 3rd bitmap\n");
/* destroy it */
- ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
+ ok(pImageList_Destroy(himl), "Failed to destroy imagelist.\n");
/* bitmaps should not be deleted by the imagelist */
ok(DeleteObject(hbm1),"bitmap 1 can't be deleted\n");
for (i = 0; i < 8; i++)
{
- himl[i] = ImageList_Create(32, 32, sizes[i], 0, 3);
+ himl[i] = pImageList_Create(32, 32, sizes[i], 0, 3);
ok(himl[i] != NULL, "failed to create himl[%d]\n", i);
- ok(0 == ImageList_AddIcon(himl[i], hicon1), "add icon1 to himl[%d] failed\n", i);
+ ok(0 == pImageList_ReplaceIcon(himl[i], -1, hicon1), "Failed to add icon1 to himl[%d].\n", i);
if (i == 0 || i == 1 || i == 7)
{
- ImageList_GetImageInfo(himl[i], 0, &info);
+ pImageList_GetImageInfo(himl[i], 0, &info);
sizes[i] = get_color_format(info.hbmImage);
}
}
for (i = 0; i < 8; i++)
for (j = 0; j < 8; j++)
{
- hmerge = ImageList_Merge(himl[i], 0, himl[j], 0, 0, 0);
+ hmerge = pImageList_Merge(himl[i], 0, himl[j], 0, 0, 0);
ok(hmerge != NULL, "merge himl[%d], himl[%d] failed\n", i, j);
- ImageList_GetImageInfo(hmerge, 0, &info);
+ pImageList_GetImageInfo(hmerge, 0, &info);
bpp = get_color_format(info.hbmImage);
/* ILC_COLOR[X] is defined as [X] */
if (i == 4 && j == 7)
"wrong biBitCount %d when merging lists %d (%d) and %d (%d)\n", bpp, i, sizes[i], j, sizes[j]);
ok(info.hbmMask != 0, "Imagelist merged from %d and %d had no mask\n", i, j);
- if (hmerge) ImageList_Destroy(hmerge);
+ pImageList_Destroy(hmerge);
}
for (i = 0; i < 8; i++)
- ImageList_Destroy(himl[i]);
+ pImageList_Destroy(himl[i]);
}
static void test_merge(void)
{
HIMAGELIST himl1, himl2, hmerge;
HICON hicon1;
- HWND hwnd = create_a_window();
+ HWND hwnd = create_window();
- himl1 = ImageList_Create(32,32,0,0,3);
+ himl1 = pImageList_Create(32, 32, 0, 0, 3);
ok(himl1 != NULL,"failed to create himl1\n");
- himl2 = ImageList_Create(32,32,0,0,3);
+ himl2 = pImageList_Create(32, 32, 0, 0, 3);
ok(himl2 != NULL,"failed to create himl2\n");
hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
if (!himl1 || !himl2 || !hicon1)
return;
- ok(0==ImageList_AddIcon(himl2, hicon1),"add icon1 to himl2 failed\n");
+ ok(0 == pImageList_ReplaceIcon(himl2, -1, hicon1), "Failed to add icon1 to himl2.\n");
check_bits(hwnd, himl2, 0, 32, icon_bits, "add icon1 to himl2");
/* If himl1 has no images, merge still succeeds */
- hmerge = ImageList_Merge(himl1, -1, himl2, 0, 0, 0);
+ hmerge = pImageList_Merge(himl1, -1, himl2, 0, 0, 0);
ok(hmerge != NULL, "merge himl1,-1 failed\n");
check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,-1");
- if (hmerge) ImageList_Destroy(hmerge);
+ pImageList_Destroy(hmerge);
- hmerge = ImageList_Merge(himl1, 0, himl2, 0, 0, 0);
+ hmerge = pImageList_Merge(himl1, 0, himl2, 0, 0, 0);
ok(hmerge != NULL,"merge himl1,0 failed\n");
check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,0");
- if (hmerge) ImageList_Destroy(hmerge);
+ pImageList_Destroy(hmerge);
/* Same happens if himl2 is empty */
- ImageList_Destroy(himl2);
- himl2 = ImageList_Create(32,32,0,0,3);
+ pImageList_Destroy(himl2);
+ himl2 = pImageList_Create(32, 32, 0, 0, 3);
ok(himl2 != NULL,"failed to recreate himl2\n");
if (!himl2)
return;
- hmerge = ImageList_Merge(himl1, -1, himl2, -1, 0, 0);
+ hmerge = pImageList_Merge(himl1, -1, himl2, -1, 0, 0);
ok(hmerge != NULL, "merge himl2,-1 failed\n");
check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,-1");
- if (hmerge) ImageList_Destroy(hmerge);
+ pImageList_Destroy(hmerge);
- hmerge = ImageList_Merge(himl1, -1, himl2, 0, 0, 0);
+ hmerge = pImageList_Merge(himl1, -1, himl2, 0, 0, 0);
ok(hmerge != NULL, "merge himl2,0 failed\n");
check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,0");
- if (hmerge) ImageList_Destroy(hmerge);
+ pImageList_Destroy(hmerge);
/* Now try merging an image with itself */
- ok(0==ImageList_AddIcon(himl2, hicon1),"re-add icon1 to himl2 failed\n");
+ ok(0 == pImageList_ReplaceIcon(himl2, -1, hicon1), "Failed to re-add icon1 to himl2.\n");
- hmerge = ImageList_Merge(himl2, 0, himl2, 0, 0, 0);
+ hmerge = pImageList_Merge(himl2, 0, himl2, 0, 0, 0);
ok(hmerge != NULL, "merge himl2 with itself failed\n");
check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2 with itself");
- if (hmerge) ImageList_Destroy(hmerge);
+ pImageList_Destroy(hmerge);
/* Try merging 2 different image lists */
- ok(0==ImageList_AddIcon(himl1, hicon1),"add icon1 to himl1 failed\n");
+ ok(0 == pImageList_ReplaceIcon(himl1, -1, hicon1), "Failed to add icon1 to himl1.\n");
- hmerge = ImageList_Merge(himl1, 0, himl2, 0, 0, 0);
+ hmerge = pImageList_Merge(himl1, 0, himl2, 0, 0, 0);
ok(hmerge != NULL, "merge himl1 with himl2 failed\n");
check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1 with himl2");
- if (hmerge) ImageList_Destroy(hmerge);
+ pImageList_Destroy(hmerge);
- hmerge = ImageList_Merge(himl1, 0, himl2, 0, 8, 16);
+ hmerge = pImageList_Merge(himl1, 0, himl2, 0, 8, 16);
ok(hmerge != NULL, "merge himl1 with himl2 8,16 failed\n");
check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1 with himl2, 8,16");
- if (hmerge) ImageList_Destroy(hmerge);
+ pImageList_Destroy(hmerge);
- ImageList_Destroy(himl1);
- ImageList_Destroy(himl2);
+ pImageList_Destroy(himl1);
+ pImageList_Destroy(himl2);
DestroyIcon(hicon1);
DestroyWindow(hwnd);
}
return IStream_Write(stream->stream, pv, cb, pcbWritten);
}
-static HRESULT STDMETHODCALLTYPE Test_Stream_Seek(IStream *iface, LARGE_INTEGER dlibMove,
- DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
+static HRESULT STDMETHODCALLTYPE Test_Stream_Seek(IStream *iface, LARGE_INTEGER offset, DWORD origin,
+ ULARGE_INTEGER *new_pos)
{
- ok(0, "unexpected call\n");
- return E_NOTIMPL;
+ struct memstream *stream = impl_from_IStream(iface);
+
+ if (is_v6_test())
+ {
+ ok(origin == STREAM_SEEK_CUR, "Unexpected origin %d.\n", origin);
+ ok(offset.QuadPart == 0, "Unexpected offset %s.\n", wine_dbgstr_longlong(offset.QuadPart));
+ ok(new_pos != NULL, "Unexpected out position pointer.\n");
+ return IStream_Seek(stream->stream, offset, origin, new_pos);
+ }
+ else
+ {
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+ }
}
static HRESULT STDMETHODCALLTYPE Test_Stream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
static void init_memstream(struct memstream *stream)
{
+ HRESULT hr;
+
stream->IStream_iface.lpVtbl = &Test_Stream_Vtbl;
- CreateStreamOnHGlobal(NULL, TRUE, &stream->stream);
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &stream->stream);
+ ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
}
static void cleanup_memstream(struct memstream *stream)
IStream_Release(stream->stream);
}
-
static INT DIB_GetWidthBytes( int width, int bpp )
{
return ((width * bpp + 31) / 8) & ~3;
}
-static ULONG check_bitmap_data(const char *bm_data, ULONG bm_data_size,
- INT width, INT height, INT bpp,
- const char *comment)
+static ULONG check_bitmap_data(const ILHEAD *header, const char *bm_data,
+ ULONG bm_data_size, const SIZE *bmpsize, INT bpp, const char *comment)
{
const BITMAPFILEHEADER *bmfh = (const BITMAPFILEHEADER *)bm_data;
const BITMAPINFOHEADER *bmih = (const BITMAPINFOHEADER *)(bm_data + sizeof(*bmfh));
ok(bmfh->bfOffBits == hdr_size, "wrong bfOffBits 0x%02x\n", bmfh->bfOffBits);
ok(bmih->biSize == sizeof(*bmih), "wrong biSize %d\n", bmih->biSize);
- ok(bmih->biWidth == width, "wrong biWidth %d (expected %d)\n", bmih->biWidth, width);
- ok(bmih->biHeight == height, "wrong biHeight %d (expected %d)\n", bmih->biHeight, height);
ok(bmih->biPlanes == 1, "wrong biPlanes %d\n", bmih->biPlanes);
ok(bmih->biBitCount == bpp, "wrong biBitCount %d\n", bmih->biBitCount);
image_size = DIB_GetWidthBytes(bmih->biWidth, bmih->biBitCount) * bmih->biHeight;
ok(bmih->biSizeImage == image_size, "wrong biSizeImage %u\n", bmih->biSizeImage);
+ ok(bmih->biWidth == bmpsize->cx && bmih->biHeight == bmpsize->cy, "Unexpected bitmap size %d x %d, "
+ "expected %d x %d\n", bmih->biWidth, bmih->biHeight, bmpsize->cx, bmpsize->cy);
if (0)
{
return hdr_size + image_size;
}
-static void check_ilhead_data(const char *ilh_data, INT cx, INT cy, INT cur, INT max, INT grow, INT flags)
+static BOOL is_v6_header(const ILHEAD *header)
{
- const ILHEAD *ilh = (const ILHEAD *)ilh_data;
+ return (header->usVersion & 0xff00) == 0x600;
+}
+static void check_ilhead_data(const ILHEAD *ilh, INT cx, INT cy, INT cur, INT max, INT grow, INT flags)
+{
ok(ilh->usMagic == IMAGELIST_MAGIC, "wrong usMagic %4x (expected %02x)\n", ilh->usMagic, IMAGELIST_MAGIC);
- ok(ilh->usVersion == 0x101, "wrong usVersion %x (expected 0x101)\n", ilh->usVersion);
+ ok(ilh->usVersion == 0x101 ||
+ ilh->usVersion == 0x600 || /* WinXP/W2k3 */
+ ilh->usVersion == 0x620, "Unknown usVersion %#x.\n", ilh->usVersion);
ok(ilh->cCurImage == cur, "wrong cCurImage %d (expected %d)\n", ilh->cCurImage, cur);
- ok(ilh->cMaxImage == max, "wrong cMaxImage %d (expected %d)\n", ilh->cMaxImage, max);
- ok(ilh->cGrow == grow, "wrong cGrow %d (expected %d)\n", ilh->cGrow, grow);
+ if (!is_v6_header(ilh))
+ {
+ ok(ilh->cMaxImage == max, "wrong cMaxImage %d (expected %d)\n", ilh->cMaxImage, max);
+ ok(ilh->cGrow == grow, "Unexpected cGrow %d (expected %d)\n", ilh->cGrow, grow);
+ }
ok(ilh->cx == cx, "wrong cx %d (expected %d)\n", ilh->cx, cx);
ok(ilh->cy == cy, "wrong cy %d (expected %d)\n", ilh->cy, cy);
ok(ilh->bkcolor == CLR_NONE, "wrong bkcolor %x\n", ilh->bkcolor);
return hbmp;
}
+static inline void imagelist_get_bitmap_size(const ILHEAD *header, SIZE *sz)
+{
+ const int tile_count = 4;
+
+ if (is_v6_header(header))
+ {
+ sz->cx = header->cx;
+ sz->cy = header->cMaxImage * header->cy;
+ }
+ else
+ {
+ sz->cx = header->cx * tile_count;
+ sz->cy = ((header->cMaxImage + tile_count - 1) / tile_count) * header->cy;
+ }
+}
+
static void check_iml_data(HIMAGELIST himl, INT cx, INT cy, INT cur, INT max, INT grow,
- INT width, INT height, INT flags, const char *comment)
+ INT flags, const char *comment)
{
INT ret, cxx, cyy, size;
struct memstream stream;
+ const ILHEAD *header;
LARGE_INTEGER mv;
HIMAGELIST himl2;
HGLOBAL hglobal;
STATSTG stat;
char *data;
HRESULT hr;
+ SIZE bmpsize;
+ BOOL b;
- ret = ImageList_GetImageCount(himl);
+ ret = pImageList_GetImageCount(himl);
ok(ret == cur, "%s: expected image count %d got %d\n", comment, cur, ret);
- ret = ImageList_GetIconSize(himl, &cxx, &cyy);
+ ret = pImageList_GetIconSize(himl, &cxx, &cyy);
ok(ret, "ImageList_GetIconSize failed\n");
ok(cxx == cx, "%s: wrong cx %d (expected %d)\n", comment, cxx, cx);
ok(cyy == cy, "%s: wrong cy %d (expected %d)\n", comment, cyy, cy);
init_memstream(&stream);
- ret = ImageList_Write(himl, &stream.IStream_iface);
- ok(ret, "%s: ImageList_Write failed\n", comment);
+ b = pImageList_Write(himl, &stream.IStream_iface);
+ ok(b, "%s: ImageList_Write failed\n", comment);
hr = GetHGlobalFromStream(stream.stream, &hglobal);
ok(hr == S_OK, "%s: Failed to get hglobal, %#x\n", comment, hr);
- IStream_Stat(stream.stream, &stat, STATFLAG_NONAME);
+ hr = IStream_Stat(stream.stream, &stat, STATFLAG_NONAME);
+ ok(hr == S_OK, "Stat() failed, hr %#x.\n", hr);
data = GlobalLock(hglobal);
ok(data != 0, "%s: ImageList_Write didn't write any data\n", comment);
ok(stat.cbSize.LowPart > sizeof(ILHEAD), "%s: ImageList_Write wrote not enough data\n", comment);
- check_ilhead_data(data, cx, cy, cur, max, grow, flags);
- size = check_bitmap_data(data + sizeof(ILHEAD), stat.cbSize.LowPart - sizeof(ILHEAD),
- width, height, flags & 0xfe, comment);
- if (size < stat.cbSize.LowPart - sizeof(ILHEAD)) /* mask is present */
+ header = (const ILHEAD *)data;
+ check_ilhead_data(header, cx, cy, cur, max, grow, flags);
+ imagelist_get_bitmap_size(header, &bmpsize);
+ size = check_bitmap_data(header, data + sizeof(ILHEAD), stat.cbSize.LowPart - sizeof(ILHEAD),
+ &bmpsize, flags & 0xfe, comment);
+ if (!is_v6_header(header) && size < stat.cbSize.LowPart - sizeof(ILHEAD)) /* mask is present */
{
ok( flags & ILC_MASK, "%s: extra data %u/%u but mask not expected\n", comment, stat.cbSize.LowPart, size );
- check_bitmap_data(data + sizeof(ILHEAD) + size, stat.cbSize.LowPart - sizeof(ILHEAD) - size,
- width, height, 1, comment);
+ check_bitmap_data(header, data + sizeof(ILHEAD) + size, stat.cbSize.LowPart - sizeof(ILHEAD) - size,
+ &bmpsize, 1, comment);
}
/* rewind and reconstruct from stream */
mv.QuadPart = 0;
IStream_Seek(stream.stream, mv, STREAM_SEEK_SET, NULL);
- himl2 = ImageList_Read(&stream.IStream_iface);
+ himl2 = pImageList_Read(&stream.IStream_iface);
ok(himl2 != NULL, "%s: Failed to deserialize imagelist\n", comment);
- ImageList_Destroy(himl2);
+ pImageList_Destroy(himl2);
GlobalUnlock(hglobal);
cleanup_memstream(&stream);
static const struct test_data
{
BYTE grey;
- INT cx, cy, cur, max, grow, width, height, bpp;
+ INT cx, cy, cur, max, grow, bpp;
const char *comment;
} td[] =
{
- { 255, BMP_CX, BMP_CX, 1, 2, 4, BMP_CX * 4, BMP_CX * 1, 24, "total 1" },
- { 170, BMP_CX, BMP_CX, 2, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 2" },
- { 85, BMP_CX, BMP_CX, 3, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 3" },
- { 0, BMP_CX, BMP_CX, 4, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 4" },
- { 0, BMP_CX, BMP_CX, 5, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 5" },
- { 85, BMP_CX, BMP_CX, 6, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 6" },
- { 170, BMP_CX, BMP_CX, 7, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 7" },
- { 255, BMP_CX, BMP_CX, 8, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 8" },
- { 255, BMP_CX, BMP_CX, 9, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 9" },
- { 170, BMP_CX, BMP_CX, 10, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 10" },
- { 85, BMP_CX, BMP_CX, 11, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 11" },
- { 0, BMP_CX, BMP_CX, 12, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 12" },
- { 0, BMP_CX, BMP_CX, 13, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 13" },
- { 85, BMP_CX, BMP_CX, 14, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 14" },
- { 170, BMP_CX, BMP_CX, 15, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 15" },
- { 255, BMP_CX, BMP_CX, 16, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 16" },
- { 255, BMP_CX, BMP_CX, 17, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 17" },
- { 170, BMP_CX, BMP_CX, 18, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 18" },
- { 85, BMP_CX, BMP_CX, 19, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 19" },
- { 0, BMP_CX, BMP_CX, 20, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 20" },
- { 0, BMP_CX, BMP_CX, 21, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 21" },
- { 85, BMP_CX, BMP_CX, 22, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "total 22" },
- { 170, BMP_CX, BMP_CX, 23, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "total 23" },
- { 255, BMP_CX, BMP_CX, 24, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "total 24" }
+ { 255, BMP_CX, BMP_CX, 1, 2, 4, 24, "total 1" },
+ { 170, BMP_CX, BMP_CX, 2, 7, 4, 24, "total 2" },
+ { 85, BMP_CX, BMP_CX, 3, 7, 4, 24, "total 3" },
+ { 0, BMP_CX, BMP_CX, 4, 7, 4, 24, "total 4" },
+ { 0, BMP_CX, BMP_CX, 5, 7, 4, 24, "total 5" },
+ { 85, BMP_CX, BMP_CX, 6, 7, 4, 24, "total 6" },
+ { 170, BMP_CX, BMP_CX, 7, 12, 4, 24, "total 7" },
+ { 255, BMP_CX, BMP_CX, 8, 12, 4, 24, "total 8" },
+ { 255, BMP_CX, BMP_CX, 9, 12, 4, 24, "total 9" },
+ { 170, BMP_CX, BMP_CX, 10, 12, 4, 24, "total 10" },
+ { 85, BMP_CX, BMP_CX, 11, 12, 4, 24, "total 11" },
+ { 0, BMP_CX, BMP_CX, 12, 17, 4, 24, "total 12" },
+ { 0, BMP_CX, BMP_CX, 13, 17, 4, 24, "total 13" },
+ { 85, BMP_CX, BMP_CX, 14, 17, 4, 24, "total 14" },
+ { 170, BMP_CX, BMP_CX, 15, 17, 4, 24, "total 15" },
+ { 255, BMP_CX, BMP_CX, 16, 17, 4, 24, "total 16" },
+ { 255, BMP_CX, BMP_CX, 17, 22, 4, 24, "total 17" },
+ { 170, BMP_CX, BMP_CX, 18, 22, 4, 24, "total 18" },
+ { 85, BMP_CX, BMP_CX, 19, 22, 4, 24, "total 19" },
+ { 0, BMP_CX, BMP_CX, 20, 22, 4, 24, "total 20" },
+ { 0, BMP_CX, BMP_CX, 21, 22, 4, 24, "total 21" },
+ { 85, BMP_CX, BMP_CX, 22, 27, 4, 24, "total 22" },
+ { 170, BMP_CX, BMP_CX, 23, 27, 4, 24, "total 23" },
+ { 255, BMP_CX, BMP_CX, 24, 27, 4, 24, "total 24" }
};
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, 4, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "total 0");
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, 4, ILC_COLOR24, "total 0");
#define add_bitmap(grey) \
sprintf(comment, "%d", n++); \
for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
{
add_bitmap(td[i].grey);
- check_iml_data(himl, td[i].cx, td[i].cy, td[i].cur, td[i].max, td[i].grow,
- td[i].width, td[i].height, td[i].bpp, td[i].comment);
+ check_iml_data(himl, td[i].cx, td[i].cy, td[i].cur, td[i].max, td[i].grow, td[i].bpp, td[i].comment);
}
#undef add_bitmap
}
HICON icon;
INT ret;
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 1, 1);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 1, 1);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, 4, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "empty");
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, 4, ILC_COLOR24, "empty");
image_list_init(himl);
- check_iml_data(himl, BMP_CX, BMP_CX, 24, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "orig");
+ check_iml_data(himl, BMP_CX, BMP_CX, 24, 27, 4, ILC_COLOR24, "orig");
- ret = ImageList_Remove(himl, 4);
+ ret = pImageList_Remove(himl, 4);
ok(ret, "ImageList_Remove failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 23, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "1");
+ check_iml_data(himl, BMP_CX, BMP_CX, 23, 27, 4, ILC_COLOR24, "1");
- ret = ImageList_Remove(himl, 5);
+ ret = pImageList_Remove(himl, 5);
ok(ret, "ImageList_Remove failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 22, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "2");
+ check_iml_data(himl, BMP_CX, BMP_CX, 22, 27, 4, ILC_COLOR24, "2");
- ret = ImageList_Remove(himl, 6);
+ ret = pImageList_Remove(himl, 6);
ok(ret, "ImageList_Remove failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 21, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "3");
+ check_iml_data(himl, BMP_CX, BMP_CX, 21, 27, 4, ILC_COLOR24, "3");
- ret = ImageList_Remove(himl, 7);
+ ret = pImageList_Remove(himl, 7);
ok(ret, "ImageList_Remove failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "4");
+ check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, ILC_COLOR24, "4");
- ret = ImageList_Remove(himl, -2);
+ ret = pImageList_Remove(himl, -2);
ok(!ret, "ImageList_Remove(-2) should fail\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "5");
+ check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, ILC_COLOR24, "5");
- ret = ImageList_Remove(himl, 20);
+ ret = pImageList_Remove(himl, 20);
ok(!ret, "ImageList_Remove(20) should fail\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "6");
+ check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, ILC_COLOR24, "6");
- ret = ImageList_Remove(himl, -1);
+ ret = pImageList_Remove(himl, -1);
ok(ret, "ImageList_Remove(-1) failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 4, 4, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "7");
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 4, 4, ILC_COLOR24, "7");
- ret = ImageList_Destroy(himl);
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
/* test ImageList_Create storage allocation */
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 0, 32);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 0, 32);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 1, 32, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "init 0 grow 32");
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 1, 32, ILC_COLOR24, "init 0 grow 32");
hbm = create_bitmap(BMP_CX * 9, BMP_CX, 0, "9");
- ret = ImageList_Add(himl, hbm, NULL);
+ ret = pImageList_Add(himl, hbm, NULL);
ok(ret == 0, "ImageList_Add returned %d, expected 0\n", ret);
- check_iml_data(himl, BMP_CX, BMP_CX, 1, 34, 32, BMP_CX * 4, BMP_CX * 9, ILC_COLOR24, "add 1 x 9");
+ check_iml_data(himl, BMP_CX, BMP_CX, 1, 34, 32, ILC_COLOR24, "add 1 x 9");
DeleteObject(hbm);
- ret = ImageList_Destroy(himl);
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 4, 4);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 4, 4);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24, "init 4 grow 4");
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, ILC_COLOR24, "init 4 grow 4");
hbm = create_bitmap(BMP_CX, BMP_CX * 9, 0, "9");
- ret = ImageList_Add(himl, hbm, NULL);
+ ret = pImageList_Add(himl, hbm, NULL);
ok(ret == 0, "ImageList_Add returned %d, expected 0\n", ret);
- check_iml_data(himl, BMP_CX, BMP_CX, 9, 15, 4, BMP_CX * 4, BMP_CX * 4, ILC_COLOR24, "add 9 x 1");
- ret = ImageList_Add(himl, hbm, NULL);
+ check_iml_data(himl, BMP_CX, BMP_CX, 9, 15, 4, ILC_COLOR24, "add 9 x 1");
+ ret = pImageList_Add(himl, hbm, NULL);
ok(ret == 9, "ImageList_Add returned %d, expected 9\n", ret);
- check_iml_data(himl, BMP_CX, BMP_CX, 18, 25, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "add 9 x 1");
+ check_iml_data(himl, BMP_CX, BMP_CX, 18, 25, 4, ILC_COLOR24, "add 9 x 1");
DeleteObject(hbm);
- ret = ImageList_Destroy(himl);
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 207, 209);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 207, 209);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 208, 212, BMP_CX * 4, BMP_CX * 52, ILC_COLOR24, "init 207 grow 209");
- ret = ImageList_Destroy(himl);
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 208, 212, ILC_COLOR24, "init 207 grow 209");
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 209, 207);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 209, 207);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 210, 208, BMP_CX * 4, BMP_CX * 53, ILC_COLOR24, "init 209 grow 207");
- ret = ImageList_Destroy(himl);
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 210, 208, ILC_COLOR24, "init 209 grow 207");
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 14, 4);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 14, 4);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 15, 4, BMP_CX * 4, BMP_CX * 4, ILC_COLOR24, "init 14 grow 4");
- ret = ImageList_Destroy(himl);
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 15, 4, ILC_COLOR24, "init 14 grow 4");
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 5, 9);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 5, 9);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 6, 12, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24, "init 5 grow 9");
- ret = ImageList_Destroy(himl);
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 6, 12, ILC_COLOR24, "init 5 grow 9");
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 9, 5);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 9, 5);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 10, 8, BMP_CX * 4, BMP_CX * 3, ILC_COLOR24, "init 9 grow 5");
- ret = ImageList_Destroy(himl);
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 10, 8, ILC_COLOR24, "init 9 grow 5");
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 2, 4);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 2, 4);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 4, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "init 2 grow 4");
- ret = ImageList_Destroy(himl);
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 4, ILC_COLOR24, "init 2 grow 4");
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 4, 2);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 4, 2);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24, "init 4 grow 2");
- ret = ImageList_Destroy(himl);
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, ILC_COLOR24, "init 4 grow 2");
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR8, 4, 2);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR8, 4, 2);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR8, "bpp 8");
- ret = ImageList_Destroy(himl);
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, ILC_COLOR8, "bpp 8");
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4, 4, 2);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4, 4, 2);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4, "bpp 4");
- ret = ImageList_Destroy(himl);
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, ILC_COLOR4, "bpp 4");
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, 0, 4, 2);
+ himl = pImageList_Create(BMP_CX, BMP_CX, 0, 4, 2);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4, "bpp default");
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, ILC_COLOR4, "bpp default");
icon = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
- ok( ImageList_AddIcon(himl, icon) == 0,"failed to add icon\n");
- ok( ImageList_AddIcon(himl, icon) == 1,"failed to add icon\n");
+ ok( pImageList_ReplaceIcon(himl, -1, icon) == 0, "Failed to add icon.\n");
+ ok( pImageList_ReplaceIcon(himl, -1, icon) == 1, "Failed to add icon.\n");
DestroyIcon( icon );
- check_iml_data(himl, BMP_CX, BMP_CX, 2, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4, "bpp default");
- ret = ImageList_Destroy(himl);
+ check_iml_data(himl, BMP_CX, BMP_CX, 2, 5, 4, ILC_COLOR4, "bpp default");
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24|ILC_MASK, 4, 2);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24|ILC_MASK, 4, 2);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24|ILC_MASK,
- "bpp 24 + mask");
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, ILC_COLOR24|ILC_MASK, "bpp 24 + mask");
icon = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
- ok( ImageList_AddIcon(himl, icon) == 0,"failed to add icon\n");
- ok( ImageList_AddIcon(himl, icon) == 1,"failed to add icon\n");
+ ok( pImageList_ReplaceIcon(himl, -1, icon) == 0, "Failed to add icon.\n");
+ ok( pImageList_ReplaceIcon(himl, -1, icon) == 1, "Failed to add icon.\n");
DestroyIcon( icon );
- check_iml_data(himl, BMP_CX, BMP_CX, 2, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24|ILC_MASK,
- "bpp 24 + mask");
- ret = ImageList_Destroy(himl);
+ check_iml_data(himl, BMP_CX, BMP_CX, 2, 5, 4, ILC_COLOR24|ILC_MASK, "bpp 24 + mask");
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 4, 2);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 4, 2);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4|ILC_MASK,
- "bpp 4 + mask");
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, ILC_COLOR4|ILC_MASK, "bpp 4 + mask");
icon = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
- ok( ImageList_AddIcon(himl, icon) == 0,"failed to add icon\n");
- ok( ImageList_AddIcon(himl, icon) == 1,"failed to add icon\n");
+ ok( pImageList_ReplaceIcon(himl, -1, icon) == 0, "Failed to add icon.\n");
+ ok( pImageList_ReplaceIcon(himl, -1, icon) == 1, "Failed to add icon.\n");
DestroyIcon( icon );
- check_iml_data(himl, BMP_CX, BMP_CX, 2, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4|ILC_MASK,
- "bpp 4 + mask");
- ret = ImageList_Destroy(himl);
+ check_iml_data(himl, BMP_CX, BMP_CX, 2, 5, 4, ILC_COLOR4|ILC_MASK, "bpp 4 + mask");
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, 99);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, 99);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 100, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
- "init 2 grow 99");
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 100, ILC_COLOR4|ILC_MASK, "init 2 grow 99");
icon = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
- ok( ImageList_AddIcon(himl, icon) == 0,"failed to add icon\n");
- ok( ImageList_AddIcon(himl, icon) == 1,"failed to add icon\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 2, 3, 100, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
- "init 2 grow 99 2 icons");
- ok( ImageList_AddIcon(himl, icon) == 2,"failed to add icon\n");
+ ok( pImageList_ReplaceIcon(himl, -1, icon) == 0, "Failed to add icon.\n");
+ ok( pImageList_ReplaceIcon(himl, -1, icon) == 1, "Failed to add icon.\n");
+ check_iml_data(himl, BMP_CX, BMP_CX, 2, 3, 100, ILC_COLOR4|ILC_MASK, "init 2 grow 99 2 icons");
+ ok( pImageList_ReplaceIcon(himl, -1, icon) == 2, "Failed to add icon\n");
DestroyIcon( icon );
- check_iml_data(himl, BMP_CX, BMP_CX, 3, 104, 100, BMP_CX * 4, BMP_CX * 104/4, ILC_COLOR4|ILC_MASK,
- "init 2 grow 99 3 icons");
- ok( ImageList_Remove(himl, -1) == TRUE,"failed to remove icon\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 100, 100, BMP_CX * 4, BMP_CX * 100/4, ILC_COLOR4|ILC_MASK,
- "init 2 grow 99 empty");
- ok( ImageList_SetImageCount(himl, 22) == TRUE,"failed to set image count\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 22, 23, 100, BMP_CX * 4, BMP_CX * 24/4, ILC_COLOR4|ILC_MASK,
- "init 2 grow 99 set count 22");
- ok( ImageList_SetImageCount(himl, 0) == TRUE,"failed to set image count\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 1, 100, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
- "init 2 grow 99 set count 0");
- ok( ImageList_SetImageCount(himl, 42) == TRUE,"failed to set image count\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 42, 43, 100, BMP_CX * 4, BMP_CX * 44/4, ILC_COLOR4|ILC_MASK,
- "init 2 grow 99 set count 42");
- ret = ImageList_Destroy(himl);
+ check_iml_data(himl, BMP_CX, BMP_CX, 3, 104, 100, ILC_COLOR4|ILC_MASK, "init 2 grow 99 3 icons");
+ ok( pImageList_Remove(himl, -1) == TRUE, "Failed to remove icon.\n");
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 100, 100, ILC_COLOR4|ILC_MASK, "init 2 grow 99 empty");
+ ok( pImageList_SetImageCount(himl, 22) == TRUE, "Failed to set image count.\n");
+ check_iml_data(himl, BMP_CX, BMP_CX, 22, 23, 100, ILC_COLOR4|ILC_MASK, "init 2 grow 99 set count 22");
+ ok( pImageList_SetImageCount(himl, 0) == TRUE, "Failed to set image count.\n");
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 1, 100, ILC_COLOR4|ILC_MASK, "init 2 grow 99 set count 0");
+ ok( pImageList_SetImageCount(himl, 42) == TRUE, "Failed to set image count.\n");
+ check_iml_data(himl, BMP_CX, BMP_CX, 42, 43, 100, ILC_COLOR4|ILC_MASK, "init 2 grow 99 set count 42");
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, 65536+12);
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, -20);
ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 12, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
- "init 2 grow 65536+12");
- ret = ImageList_Destroy(himl);
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 4, ILC_COLOR4|ILC_MASK, "init 2 grow -20");
+ ret = pImageList_Destroy(himl);
ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, 65535);
- ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 0, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
- "init 2 grow 65535");
- ret = ImageList_Destroy(himl);
- ok(ret, "ImageList_Destroy failed\n");
+ /* Version 6 implementation hangs on large grow values. */
+ if (!is_v6_test())
+ {
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, 65536+12);
+ ok(himl != 0, "ImageList_Create failed\n");
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 12, ILC_COLOR4|ILC_MASK, "init 2 grow 65536+12");
+ ret = pImageList_Destroy(himl);
+ ok(ret, "ImageList_Destroy failed\n");
- himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, -20);
- ok(himl != 0, "ImageList_Create failed\n");
- check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 4, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
- "init 2 grow -20");
- ret = ImageList_Destroy(himl);
- ok(ret, "ImageList_Destroy failed\n");
+ himl = pImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, 65535);
+ ok(himl != 0, "ImageList_Create failed\n");
+ check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 0, ILC_COLOR4|ILC_MASK, "init 2 grow 65535");
+ ret = pImageList_Destroy(himl);
+ ok(ret, "ImageList_Destroy failed\n");
+ }
}
static void test_shell_imagelist(void)
if (hr == S_OK)
IImageList_Release(imgl);
- ImageList_Destroy(himl);
+ pImageList_Destroy(himl);
/* IImageList2 */
hr = pImageList_CoCreateInstance(&CLSID_ImageList, NULL, &IID_IImageList2, (void**)&imagelist);
IImageList2_Release(imagelist);
}
-static void test_hotspot_v6(void)
-{
- struct hotspot {
- int dx;
- int dy;
- };
-
-#define SIZEX1 47
-#define SIZEY1 31
-#define SIZEX2 11
-#define SIZEY2 17
-#define HOTSPOTS_MAX 4 /* Number of entries in hotspots */
- static const struct hotspot hotspots[HOTSPOTS_MAX] = {
- { 10, 7 },
- { SIZEX1, SIZEY1 },
- { -9, -8 },
- { -7, 35 }
- };
- int i, j;
- HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1);
- HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2);
- IImageList *imgl1, *imgl2;
- HRESULT hr;
-
- /* cast to IImageList */
- imgl1 = (IImageList *) himl1;
- imgl2 = (IImageList *) himl2;
-
- for (i = 0; i < HOTSPOTS_MAX; i++) {
- for (j = 0; j < HOTSPOTS_MAX; j++) {
- int dx1 = hotspots[i].dx;
- int dy1 = hotspots[i].dy;
- int dx2 = hotspots[j].dx;
- int dy2 = hotspots[j].dy;
- int correctx, correcty, newx, newy;
- char loc[256];
- IImageList *imglNew;
- POINT ppt;
-
- hr = IImageList_BeginDrag(imgl1, 0, dx1, dy1);
- ok(SUCCEEDED(hr), "BeginDrag failed for { %d, %d }\n", dx1, dy1);
- sprintf(loc, "BeginDrag (%d,%d)\n", i, j);
-
- /* check merging the dragged image with a second image */
- hr = IImageList_SetDragCursorImage(imgl2, (IUnknown *) imgl2, 0, dx2, dy2);
- ok(SUCCEEDED(hr), "SetDragCursorImage failed for {%d, %d}{%d, %d}\n",
- dx1, dy1, dx2, dy2);
- sprintf(loc, "SetDragCursorImage (%d,%d)\n", i, j);
-
- /* check new hotspot, it should be the same like the old one */
- hr = IImageList_GetDragImage(imgl2, NULL, &ppt, &IID_IImageList, (PVOID *) &imglNew);
- ok(SUCCEEDED(hr), "GetDragImage failed\n");
- ok(ppt.x == dx1 && ppt.y == dy1,
- "Expected drag hotspot [%d,%d] got [%d,%d]\n",
- dx1, dy1, ppt.x, ppt.y);
- /* check size of new dragged image */
- IImageList_GetIconSize(imglNew, &newx, &newy);
- correctx = max(SIZEX1, max(SIZEX2 + dx2, SIZEX1 - dx2));
- correcty = max(SIZEY1, max(SIZEY2 + dy2, SIZEY1 - dy2));
- ok(newx == correctx && newy == correcty,
- "Expected drag image size [%d,%d] got [%d,%d]\n",
- correctx, correcty, newx, newy);
- sprintf(loc, "GetDragImage (%d,%d)\n", i, j);
- IImageList_EndDrag(imgl2);
- }
- }
-#undef SIZEX1
-#undef SIZEY1
-#undef SIZEX2
-#undef SIZEY2
-#undef HOTSPOTS_MAX
- IImageList_Release(imgl2);
- IImageList_Release(imgl1);
-}
-
static void test_IImageList_Add_Remove(void)
{
IImageList *imgl;
HDC hdc;
int ret;
- hwndfortest = create_a_window();
+ hwndfortest = create_window();
hdc = GetDC(hwndfortest);
ok(hdc!=NULL, "couldn't get DC\n");
HIMAGELIST himl1, himl2;
IImageList *imgl1, *imgl2, *merge;
HICON hicon1;
- HWND hwnd = create_a_window();
+ HWND hwnd = create_window();
HRESULT hr;
int ret;
INT cx, cy;
BOOL ret;
- himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
+ himl = pImageList_Create(16, 16, ILC_COLOR16, 0, 3);
/* null pointers, not zero imagelist dimensions */
- ret = ImageList_GetIconSize(himl, NULL, NULL);
+ ret = pImageList_GetIconSize(himl, NULL, NULL);
ok(!ret, "got %d\n", ret);
/* doesn't touch return pointers */
cx = 0x1abe11ed;
- ret = ImageList_GetIconSize(himl, &cx, NULL);
+ ret = pImageList_GetIconSize(himl, &cx, NULL);
ok(!ret, "got %d\n", ret);
ok(cx == 0x1abe11ed, "got %d\n", cx);
cy = 0x1abe11ed;
- ret = ImageList_GetIconSize(himl, NULL, &cy);
+ ret = pImageList_GetIconSize(himl, NULL, &cy);
ok(!ret, "got %d\n", ret);
ok(cy == 0x1abe11ed, "got %d\n", cy);
- ImageList_Destroy(himl);
+ pImageList_Destroy(himl);
- ret = ImageList_GetIconSize((HIMAGELIST)0xdeadbeef, &cx, &cy);
+ ret = pImageList_GetIconSize((HIMAGELIST)0xdeadbeef, &cx, &cy);
ok(!ret, "got %d\n", ret);
}
static void test_create_destroy(void)
{
HIMAGELIST himl;
- IImageList *imgl;
INT cx, cy;
BOOL rc;
- HRESULT hr;
INT ret;
/* list with zero or negative image dimensions */
- himl = ImageList_Create(0, 0, ILC_COLOR16, 0, 3);
+ himl = pImageList_Create(0, 0, ILC_COLOR16, 0, 3);
ok(himl == NULL, "got %p\n", himl);
- himl = ImageList_Create(0, 16, ILC_COLOR16, 0, 3);
+ himl = pImageList_Create(0, 16, ILC_COLOR16, 0, 3);
ok(himl == NULL, "got %p\n", himl);
- himl = ImageList_Create(16, 0, ILC_COLOR16, 0, 3);
+ himl = pImageList_Create(16, 0, ILC_COLOR16, 0, 3);
ok(himl == NULL, "got %p\n", himl);
- himl = ImageList_Create(16, -1, ILC_COLOR16, 0, 3);
+ himl = pImageList_Create(16, -1, ILC_COLOR16, 0, 3);
ok(himl == NULL, "got %p\n", himl);
- himl = ImageList_Create(-1, 16, ILC_COLOR16, 0, 3);
+ himl = pImageList_Create(-1, 16, ILC_COLOR16, 0, 3);
ok(himl == NULL, "got %p\n", himl);
- rc = ImageList_Destroy((HIMAGELIST)0xdeadbeef);
+ rc = pImageList_Destroy((HIMAGELIST)0xdeadbeef);
ok(rc == FALSE, "ImageList_Destroy(0xdeadbeef) should fail and not crash\n");
/* DDB image lists */
- himl = ImageList_Create(0, 14, ILC_COLORDDB, 4, 4);
+ himl = pImageList_Create(0, 14, ILC_COLORDDB, 4, 4);
ok(himl != NULL, "got %p\n", himl);
- imgl = (IImageList*)himl;
- IImageList_GetIconSize(imgl, &cx, &cy);
+
+ pImageList_GetIconSize(himl, &cx, &cy);
ok (cx == 0, "Wrong cx (%i)\n", cx);
ok (cy == 14, "Wrong cy (%i)\n", cy);
- ImageList_Destroy(himl);
+ pImageList_Destroy(himl);
- himl = ImageList_Create(0, 0, ILC_COLORDDB, 4, 4);
+ himl = pImageList_Create(0, 0, ILC_COLORDDB, 4, 4);
ok(himl != NULL, "got %p\n", himl);
- imgl = (IImageList*)himl;
- IImageList_GetIconSize(imgl, &cx, &cy);
+ pImageList_GetIconSize(himl, &cx, &cy);
ok (cx == 0, "Wrong cx (%i)\n", cx);
ok (cy == 0, "Wrong cy (%i)\n", cy);
- ImageList_Destroy(himl);
+ pImageList_Destroy(himl);
- himl = ImageList_Create(0, 0, ILC_COLORDDB, 0, 4);
+ himl = pImageList_Create(0, 0, ILC_COLORDDB, 0, 4);
ok(himl != NULL, "got %p\n", himl);
- imgl = (IImageList*)himl;
- IImageList_GetIconSize(imgl, &cx, &cy);
+ pImageList_GetIconSize(himl, &cx, &cy);
ok (cx == 0, "Wrong cx (%i)\n", cx);
ok (cy == 0, "Wrong cy (%i)\n", cy);
- hr = IImageList_SetImageCount(imgl, 3);
- ok(hr == S_OK, "got 0x%08x\n", hr);
- hr = IImageList_GetImageCount(imgl, &ret);
- ok(hr == S_OK && ret == 3, "invalid image count after increase\n");
+ pImageList_SetImageCount(himl, 3);
+ ret = pImageList_GetImageCount(himl);
+ ok(ret == 3, "Unexpected image count after increase\n");
/* Trying to actually add an image causes a crash on Windows */
- ImageList_Destroy(himl);
+ pImageList_Destroy(himl);
/* Negative values fail */
- himl = ImageList_Create(-1, -1, ILC_COLORDDB, 4, 4);
+ himl = pImageList_Create(-1, -1, ILC_COLORDDB, 4, 4);
ok(himl == NULL, "got %p\n", himl);
- himl = ImageList_Create(-1, 1, ILC_COLORDDB, 4, 4);
+ himl = pImageList_Create(-1, 1, ILC_COLORDDB, 4, 4);
ok(himl == NULL, "got %p\n", himl);
- himl = ImageList_Create(1, -1, ILC_COLORDDB, 4, 4);
+ himl = pImageList_Create(1, -1, ILC_COLORDDB, 4, 4);
ok(himl == NULL, "got %p\n", himl);
}
BITMAPINFO *bmi = (BITMAPINFO *)bmi_buffer;
int i, depth = ilc & 0xfe;
- ret = ImageList_GetImageInfo(himl, 0, &info);
+ ret = pImageList_GetImageInfo(himl, 0, &info);
ok(ret, "got %d\n", ret);
ok(info.hbmImage != NULL, "got %p\n", info.hbmImage);
ok((bmi->bmiColors[i].rgbRed == expect[i].rgbRed &&
bmi->bmiColors[i].rgbGreen == expect[i].rgbGreen &&
bmi->bmiColors[i].rgbBlue == expect[i].rgbBlue) ||
- (broken_expect && broken(bmi->bmiColors[i].rgbRed == broken_expect[i].rgbRed &&
+ broken(bmi->bmiColors[i].rgbRed == broken_expect[i].rgbRed &&
bmi->bmiColors[i].rgbGreen == broken_expect[i].rgbGreen &&
- bmi->bmiColors[i].rgbBlue == broken_expect[i].rgbBlue)),
+ bmi->bmiColors[i].rgbBlue == broken_expect[i].rgbBlue),
"%d: %s: got color[%d] %02x %02x %02x expect %02x %02x %02x\n", depth, name, i,
bmi->bmiColors[i].rgbRed, bmi->bmiColors[i].rgbGreen, bmi->bmiColors[i].rgbBlue,
expect[i].rgbRed, expect[i].rgbGreen, expect[i].rgbBlue);
get_default_color_table(hdc, ilc & 0xfe, default_table);
- himl = ImageList_Create(16, 16, ilc, 0, 3);
+ himl = pImageList_Create(16, 16, ilc, 0, 3);
ok(himl != NULL, "got %p\n", himl);
memset(bmi_buffer, 0, sizeof(bmi_buffer));
dib32 = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, NULL, 0);
/* add 32 first then 8. This won't set the color table */
- ret = ImageList_Add(himl, dib32, NULL);
+ ret = pImageList_Add(himl, dib32, NULL);
ok(ret == 0, "got %d\n", ret);
- ret = ImageList_Add(himl, dib8, NULL);
+ ret = pImageList_Add(himl, dib8, NULL);
ok(ret == 1, "got %d\n", ret);
check_color_table("add 32, 8", hdc, himl, ilc, default_table, NULL);
/* since the previous _Adds didn't set the color table, this one will */
- ret = ImageList_Remove(himl, -1);
+ ret = pImageList_Remove(himl, -1);
ok(ret, "got %d\n", ret);
- ret = ImageList_Add(himl, dib8, NULL);
+ ret = pImageList_Add(himl, dib8, NULL);
ok(ret == 0, "got %d\n", ret);
memset(rgb, 0, sizeof(rgb));
/* remove all, add 4. Color table remains the same since it's inplicitly
been set by the previous _Add */
- ret = ImageList_Remove(himl, -1);
+ ret = pImageList_Remove(himl, -1);
ok(ret, "got %d\n", ret);
- ret = ImageList_Add(himl, dib4, NULL);
+ ret = pImageList_Add(himl, dib4, NULL);
ok(ret == 0, "got %d\n", ret);
check_color_table("remove all, add 4", hdc, himl, ilc, rgb, default_table);
- ImageList_Destroy(himl);
- himl = ImageList_Create(16, 16, ilc, 0, 3);
+ pImageList_Destroy(himl);
+ himl = pImageList_Create(16, 16, ilc, 0, 3);
ok(himl != NULL, "got %p\n", himl);
/* add 4 */
- ret = ImageList_Add(himl, dib4, NULL);
+ ret = pImageList_Add(himl, dib4, NULL);
ok(ret == 0, "got %d\n", ret);
memset(rgb, 0, 16 * sizeof(rgb[0]));
check_color_table("add 4", hdc, himl, ilc, rgb, default_table);
- ImageList_Destroy(himl);
- himl = ImageList_Create(16, 16, ilc, 0, 3);
+ pImageList_Destroy(himl);
+ himl = pImageList_Create(16, 16, ilc, 0, 3);
ok(himl != NULL, "got %p\n", himl);
/* set color table, add 8 */
- ret = ImageList_Remove(himl, -1);
+ ret = pImageList_Remove(himl, -1);
ok(ret, "got %d\n", ret);
memset(rgb, 0, sizeof(rgb));
rgb[0].rgbRed = 0xcc;
ret = pImageList_SetColorTable(himl, 0, 2, rgb);
ok(ret == 2, "got %d\n", ret);
/* the table is set, so this doesn't change it */
- ret = ImageList_Add(himl, dib8, NULL);
+ ret = pImageList_Add(himl, dib8, NULL);
ok(ret == 0, "got %d\n", ret);
memcpy(rgb + 2, default_table + 2, 254 * sizeof(rgb[0]));
DeleteObject(dib8);
DeleteObject(dib4);
DeleteDC(hdc);
- ImageList_Destroy(himl);
+ pImageList_Destroy(himl);
}
static void test_copy(void)
BOOL ret;
int count;
- dst = ImageList_Create(5, 11, ILC_COLOR, 1, 1);
- count = ImageList_GetImageCount(dst);
+ dst = pImageList_Create(5, 11, ILC_COLOR, 1, 1);
+ count = pImageList_GetImageCount(dst);
ok(!count, "ImageList not empty.\n");
src = createImageList(7, 13);
- count = ImageList_GetImageCount(src);
+ count = pImageList_GetImageCount(src);
ok(count > 2, "Tests need an ImageList with more than 2 images\n");
/* ImageList_Copy() cannot copy between two ImageLists */
- ret = ImageList_Copy(dst, 0, src, 2, ILCF_MOVE);
+ ret = pImageList_Copy(dst, 0, src, 2, ILCF_MOVE);
ok(!ret, "ImageList_Copy() should have returned FALSE\n");
- count = ImageList_GetImageCount(dst);
+ count = pImageList_GetImageCount(dst);
ok(count == 0, "Expected no image in dst ImageList, got %d\n", count);
- ImageList_Destroy(dst);
- ImageList_Destroy(src);
+ pImageList_Destroy(dst);
+ pImageList_Destroy(src);
+}
+
+static void test_loadimage(void)
+{
+ HIMAGELIST list;
+ DWORD flags;
+
+ list = pImageList_LoadImageW( hinst, MAKEINTRESOURCEW(IDB_BITMAP_128x15), 16, 1, CLR_DEFAULT,
+ IMAGE_BITMAP, LR_CREATEDIBSECTION );
+ ok( list != NULL, "got %p\n", list );
+ flags = pImageList_GetFlags( list );
+ ok( flags == (ILC_COLOR4 | ILC_MASK), "got %08x\n", flags );
+ pImageList_Destroy( list );
+
+ list = pImageList_LoadImageW( hinst, MAKEINTRESOURCEW(IDB_BITMAP_128x15), 16, 1, CLR_NONE,
+ IMAGE_BITMAP, LR_CREATEDIBSECTION );
+ ok( list != NULL, "got %p\n", list );
+ flags = pImageList_GetFlags( list );
+ ok( flags == ILC_COLOR4, "got %08x\n", flags );
+ pImageList_Destroy( list );
}
static void test_IImageList_Clone(void)
HRESULT hr;
ULONG ref;
- himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
+ himl = pImageList_Create(16, 16, ILC_COLOR16, 0, 3);
imgl = (IImageList*)himl;
if (0)
COLORREF color;
HRESULT hr;
- himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
+ himl = pImageList_Create(16, 16, ILC_COLOR16, 0, 3);
imgl = (IImageList*)himl;
if (0)
COLORREF color;
HRESULT hr;
- himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
+ himl = pImageList_Create(16, 16, ILC_COLOR16, 0, 3);
imgl = (IImageList*)himl;
if (0)
int count;
HRESULT hr;
- himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
+ himl = pImageList_Create(16, 16, ILC_COLOR16, 0, 3);
imgl = (IImageList*)himl;
if (0)
int cx, cy;
HRESULT hr;
- himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
+ himl = pImageList_Create(16, 16, ILC_COLOR16, 0, 3);
imgl = (IImageList*)himl;
hr = IImageList_GetIconSize(imgl, NULL, NULL);
IImageList_Release(imgl);
}
+static void init_functions(void)
+{
+ HMODULE hComCtl32 = GetModuleHandleA("comctl32.dll");
+
+#define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
+#define X2(f, ord) p##f = (void*)GetProcAddress(hComCtl32, (const char *)ord);
+ X(ImageList_Create);
+ X(ImageList_Destroy);
+ X(ImageList_Add);
+ X(ImageList_DrawIndirect);
+ X(ImageList_SetImageCount);
+ X(ImageList_SetImageCount);
+ X2(ImageList_SetColorTable, 390);
+ X(ImageList_GetFlags);
+ X(ImageList_BeginDrag);
+ X(ImageList_GetDragImage);
+ X(ImageList_EndDrag);
+ X(ImageList_GetImageCount);
+ X(ImageList_SetDragCursorImage);
+ X(ImageList_GetIconSize);
+ X(ImageList_Remove);
+ X(ImageList_ReplaceIcon);
+ X(ImageList_Replace);
+ X(ImageList_Merge);
+ X(ImageList_GetImageInfo);
+ X(ImageList_Write);
+ X(ImageList_Read);
+ X(ImageList_Copy);
+ X(ImageList_LoadImageW);
+ X(ImageList_CoCreateInstance);
+ X(HIMAGELIST_QueryInterface);
+#undef X
+#undef X2
+}
+
START_TEST(imagelist)
{
ULONG_PTR ctx_cookie;
HANDLE hCtx;
- HMODULE hComCtl32 = GetModuleHandleA("comctl32.dll");
- pImageList_Create = NULL; /* These are not needed for non-v6.0 tests*/
- pImageList_Add = NULL;
- pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
- pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
- pImageList_SetColorTable = (void*)GetProcAddress(hComCtl32, (const char*)390);
+ init_functions();
hinst = GetModuleHandleA(NULL);
test_color_table(ILC_COLOR4);
test_color_table(ILC_COLOR8);
test_copy();
-
- FreeLibrary(hComCtl32);
+ test_loadimage();
/* Now perform v6 tests */
-
if (!load_v6_module(&ctx_cookie, &hCtx))
return;
- /* Reload comctl32 */
- hComCtl32 = LoadLibraryA("comctl32.dll");
- pImageList_Create = (void*)GetProcAddress(hComCtl32, "ImageList_Create");
- pImageList_Add = (void*)GetProcAddress(hComCtl32, "ImageList_Add");
- pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
- pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
- pImageList_CoCreateInstance = (void*)GetProcAddress(hComCtl32, "ImageList_CoCreateInstance");
- pHIMAGELIST_QueryInterface = (void*)GetProcAddress(hComCtl32, "HIMAGELIST_QueryInterface");
+ init_functions();
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
/* Do v6.0 tests */
+ test_add_remove();
+ test_imagecount();
+ test_DrawIndirect();
+ test_merge();
+ test_imagelist_storage();
+ test_iconsize();
+ test_color_table(ILC_COLOR4);
+ test_color_table(ILC_COLOR8);
+ test_copy();
+ test_loadimage();
+
test_ImageList_DrawIndirect();
test_shell_imagelist();
test_iimagelist();
- test_hotspot_v6();
test_IImageList_Add_Remove();
test_IImageList_Get_SetImageCount();
test_IImageList_Draw();
--- /dev/null
+/* Unit test suite for list boxes.
+ *
+ * Copyright 2003 Ferenc Wagner
+ *
+ * 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 "precomp.h"
+
+static const char * const strings[4] = {
+ "First added",
+ "Second added",
+ "Third added",
+ "Fourth added which is very long because at some time we only had a 256 byte character buffer and "
+ "that was overflowing in one of those applications that had a common dialog file open box and tried "
+ "to add a 300 characters long custom filter string which of course the code did not like and crashed. "
+ "Just make sure this string is longer than 256 characters."
+};
+
+static const char BAD_EXTENSION[] = "*.badtxt";
+
+static HWND create_listbox(DWORD add_style, HWND parent)
+{
+ INT_PTR ctl_id = 0;
+ HWND handle;
+
+ if (parent)
+ ctl_id=1;
+
+ handle = CreateWindowA("LISTBOX", "TestList", (LBS_STANDARD & ~LBS_SORT) | add_style, 0, 0, 100, 100,
+ parent, (HMENU)ctl_id, NULL, 0);
+ ok(handle != NULL, "Failed to create listbox window.\n");
+
+ SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[0]);
+ SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[1]);
+ SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[2]);
+ SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[3]);
+
+ return handle;
+}
+
+struct listbox_prop
+{
+ DWORD add_style;
+};
+
+struct listbox_stat
+{
+ int selected, anchor, caret, selcount;
+};
+
+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;
+ struct listbox_stat sel, sel_todo;
+};
+
+static void listbox_query(HWND handle, struct listbox_stat *results)
+{
+ results->selected = SendMessageA(handle, LB_GETCURSEL, 0, 0);
+ results->anchor = SendMessageA(handle, LB_GETANCHORINDEX, 0, 0);
+ results->caret = SendMessageA(handle, LB_GETCARETINDEX, 0, 0);
+ results->selcount = SendMessageA(handle, LB_GETSELCOUNT, 0, 0);
+}
+
+static void buttonpress(HWND handle, WORD x, WORD y)
+{
+ LPARAM lp = x + (y << 16);
+
+ SendMessageA(handle, WM_LBUTTONDOWN, MK_LBUTTON, lp);
+ SendMessageA(handle, WM_LBUTTONUP, 0, lp);
+}
+
+static void keypress(HWND handle, WPARAM keycode, BYTE scancode, BOOL extended)
+{
+ LPARAM lp = 1 + (scancode << 16) + (extended ? KEYEVENTF_EXTENDEDKEY : 0);
+
+ SendMessageA(handle, WM_KEYDOWN, keycode, lp);
+ SendMessageA(handle, WM_KEYUP , keycode, lp | 0xc000000);
+}
+
+#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)
+
+#define listbox_todo_field_ok(t, s, f, got) \
+ todo_wine_if (t.s##_todo.f) { listbox_field_ok(t, s, f, got); }
+
+#define listbox_ok(t, s, got) \
+ listbox_todo_field_ok(t, s, selected, got); \
+ listbox_todo_field_ok(t, s, anchor, got); \
+ 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)
+{
+ struct listbox_stat answer;
+ HWND hLB=create_listbox (test.prop.add_style, 0);
+ RECT second_item;
+ int i, res;
+
+ listbox_query (hLB, &answer);
+ listbox_ok (test, init, answer);
+
+ SendMessageA(hLB, LB_GETITEMRECT, 1, (LPARAM) &second_item);
+ buttonpress(hLB, (WORD)second_item.left, (WORD)second_item.top);
+
+ listbox_query(hLB, &answer);
+ listbox_ok(test, click, answer);
+
+ keypress(hLB, VK_DOWN, 0x50, TRUE);
+
+ listbox_query(hLB, &answer);
+ listbox_ok(test, step, answer);
+
+ DestroyWindow(hLB);
+
+ hLB = create_listbox(test.prop.add_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++)
+ {
+ DWORD size = SendMessageA(hLB, LB_GETTEXTLEN, i, 0);
+ int resA, resW;
+ WCHAR *txtw;
+ CHAR *txt;
+
+ txt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + 1);
+ resA = SendMessageA(hLB, LB_GETTEXT, i, (LPARAM)txt);
+ ok(!strcmp(txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
+
+ txtw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (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]);
+ }
+
+ HeapFree(GetProcessHeap(), 0, txtw);
+ HeapFree(GetProcessHeap(), 0, txt);
+ }
+
+ /* Confirm the count of items, and that an invalid delete does not remove anything */
+ res = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
+ ok(res == 4, "Expected 4 items, got %d\n", res);
+ res = SendMessageA(hLB, LB_DELETESTRING, -1, 0);
+ 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);
+
+ DestroyWindow(hLB);
+}
+
+static void test_item_height(void)
+{
+ INT itemHeight;
+ TEXTMETRICA tm;
+ HFONT font;
+ HWND hLB;
+ HDC hdc;
+
+ hLB = create_listbox (0, 0);
+ ok ((hdc = GetDCEx( hLB, 0, DCX_CACHE )) != 0, "Can't get hdc\n");
+ ok ((font = GetCurrentObject(hdc, OBJ_FONT)) != 0, "Can't get the current font\n");
+ ok (GetTextMetricsA( hdc, &tm ), "Can't read font metrics\n");
+ ReleaseDC( hLB, hdc);
+
+ ok (SendMessageA(hLB, WM_SETFONT, (WPARAM)font, 0) == 0, "Can't set font\n");
+
+ itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
+ ok (itemHeight == tm.tmHeight, "Item height wrong, got %d, expecting %d\n", itemHeight, tm.tmHeight);
+
+ DestroyWindow (hLB);
+
+ hLB = CreateWindowA("LISTBOX", "TestList", LBS_OWNERDRAWVARIABLE, 0, 0, 100, 100, NULL, NULL, NULL, 0);
+
+ itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
+ ok(itemHeight > 0 && itemHeight <= tm.tmHeight, "Unexpected item height %d, expected %d.\n",
+ itemHeight, tm.tmHeight);
+ itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 5, 0);
+ ok(itemHeight > 0 && itemHeight <= tm.tmHeight, "Unexpected item height %d, expected %d.\n",
+ itemHeight, tm.tmHeight);
+ itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, -5, 0);
+ ok(itemHeight > 0 && itemHeight <= tm.tmHeight, "Unexpected item height %d, expected %d.\n",
+ itemHeight, tm.tmHeight);
+
+ DestroyWindow (hLB);
+}
+
+static int got_selchange;
+
+static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_DRAWITEM:
+ {
+ RECT rc_item, rc_client, rc_clip;
+ DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
+
+ 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);
+ GetClipBox(dis->hDC, &rc_clip);
+ ok(EqualRect(&rc_client, &rc_clip) || IsRectEmpty(&rc_clip),
+ "client rect of the listbox should be equal to the clip box,"
+ "or the clip box should be empty\n");
+
+ SendMessageA(dis->hwndItem, LB_GETITEMRECT, dis->itemID, (LPARAM)&rc_item);
+ ok(EqualRect(&dis->rcItem, &rc_item), "item rects are not equal\n");
+
+ break;
+ }
+
+ case WM_COMMAND:
+ if (HIWORD( wparam ) == LBN_SELCHANGE) got_selchange++;
+ break;
+
+ default:
+ break;
+ }
+
+ return DefWindowProcA(hwnd, msg, wparam, lparam);
+}
+
+static HWND create_parent( void )
+{
+ static ATOM class;
+ WNDCLASSA cls;
+
+ if (!class)
+ {
+ cls.style = 0;
+ cls.lpfnWndProc = main_window_proc;
+ cls.cbClsExtra = 0;
+ cls.cbWndExtra = 0;
+ cls.hInstance = GetModuleHandleA(NULL);
+ cls.hIcon = 0;
+ cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
+ cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+ cls.lpszMenuName = NULL;
+ cls.lpszClassName = "main_window_class";
+ class = RegisterClassA( &cls );
+ }
+
+ return CreateWindowExA(0, "main_window_class", NULL, WS_POPUP | WS_VISIBLE, 100, 100, 400, 400, GetDesktopWindow(),
+ 0, GetModuleHandleA(NULL), NULL);
+}
+
+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);
+ assert(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 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);
+
+ DestroyWindow(hLB);
+ DestroyWindow(parent);
+}
+
+#define listbox_test_query(exp, got) \
+ ok(exp.selected == got.selected, "expected selected %d, got %d\n", exp.selected, got.selected); \
+ ok(exp.anchor == got.anchor, "expected anchor %d, got %d\n", exp.anchor, got.anchor); \
+ ok(exp.caret == got.caret, "expected caret %d, got %d\n", exp.caret, got.caret); \
+ ok(exp.selcount == got.selcount, "expected selcount %d, got %d\n", exp.selcount, got.selcount);
+
+static void test_LB_SELITEMRANGE(void)
+{
+ static const struct listbox_stat test_nosel = { 0, LB_ERR, 0, 0 };
+ static const struct listbox_stat test_1 = { 0, LB_ERR, 0, 2 };
+ static const struct listbox_stat test_2 = { 0, LB_ERR, 0, 3 };
+ static const struct listbox_stat test_3 = { 0, LB_ERR, 0, 4 };
+ struct listbox_stat answer;
+ HWND hLB;
+ INT ret;
+
+ hLB = create_listbox(LBS_EXTENDEDSEL, 0);
+ assert(hLB);
+
+ listbox_query(hLB, &answer);
+ listbox_test_query(test_nosel, answer);
+
+ ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
+ ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
+ listbox_query(hLB, &answer);
+ listbox_test_query(test_1, answer);
+
+ SendMessageA(hLB, LB_SETSEL, FALSE, -1);
+ listbox_query(hLB, &answer);
+ listbox_test_query(test_nosel, answer);
+
+ ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 4));
+ ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
+ listbox_query(hLB, &answer);
+ listbox_test_query(test_3, answer);
+
+ SendMessageA(hLB, LB_SETSEL, FALSE, -1);
+ listbox_query(hLB, &answer);
+ listbox_test_query(test_nosel, answer);
+
+ ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(-5, 5));
+ ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
+ listbox_query(hLB, &answer);
+ listbox_test_query(test_nosel, answer);
+
+ SendMessageA(hLB, LB_SETSEL, FALSE, -1);
+ listbox_query(hLB, &answer);
+ listbox_test_query(test_nosel, answer);
+
+ ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 10));
+ ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
+ listbox_query(hLB, &answer);
+ listbox_test_query(test_1, answer);
+
+ SendMessageA(hLB, LB_SETSEL, FALSE, -1);
+ listbox_query(hLB, &answer);
+ listbox_test_query(test_nosel, answer);
+
+ ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(4, 10));
+ ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
+ listbox_query(hLB, &answer);
+ listbox_test_query(test_nosel, answer);
+
+ SendMessageA(hLB, LB_SETSEL, FALSE, -1);
+ listbox_query(hLB, &answer);
+ listbox_test_query(test_nosel, answer);
+
+ ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(10, 1));
+ ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
+ listbox_query(hLB, &answer);
+ listbox_test_query(test_2, answer);
+
+ SendMessageA(hLB, LB_SETSEL, FALSE, -1);
+ listbox_query(hLB, &answer);
+ listbox_test_query(test_nosel, answer);
+
+ ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, -1));
+ ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
+ listbox_query(hLB, &answer);
+ listbox_test_query(test_2, answer);
+
+ DestroyWindow(hLB);
+}
+
+static void test_LB_SETCURSEL(void)
+{
+ HWND parent, hLB;
+ INT ret;
+
+ parent = create_parent();
+ ok(parent != NULL, "Failed to create parent window.\n");
+
+ hLB = create_listbox(LBS_NOINTEGRALHEIGHT | WS_CHILD, parent);
+ ok(hLB != NULL, "Failed to create listbox.\n");
+
+ SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 32);
+
+ 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_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);
+
+ DestroyWindow(hLB);
+}
+
+static void test_listbox_height(void)
+{
+ HWND hList;
+ int r, id;
+
+ hList = CreateWindowA( "ListBox", "list test", 0,
+ 1, 1, 600, 100, NULL, NULL, NULL, NULL );
+ ok( hList != NULL, "failed to create listbox\n");
+
+ id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
+ ok( id == 0, "item id wrong\n");
+
+ r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 20, 0 ));
+ ok( r == 0, "send message failed\n");
+
+ r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
+ ok( r == 20, "height wrong\n");
+
+ r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0, 30 ));
+ ok( r == -1, "send message failed\n");
+
+ r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
+ ok( r == 20, "height wrong\n");
+
+ r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 256, 0 ));
+ ok( r == -1, "Failed to set item height, %d.\n", r);
+
+ r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
+ ok( r == 20, "Unexpected item height %d.\n", r);
+
+ r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0xff, 0 ));
+ ok( r == 0, "send message failed\n");
+
+ r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
+ ok( r == 0xff, "height wrong\n");
+
+ DestroyWindow( hList );
+}
+
+static void test_itemfrompoint(void)
+{
+ /* WS_POPUP is required in order to have a more accurate size calculation (
+ without caption). LBS_NOINTEGRALHEIGHT is required in order to test
+ behavior of partially-displayed item.
+ */
+ HWND hList = CreateWindowA( "ListBox", "list test",
+ WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT,
+ 1, 1, 600, 100, NULL, NULL, NULL, NULL );
+ ULONG r, id;
+ RECT rc;
+
+ /* For an empty listbox win2k returns 0x1ffff, win98 returns 0x10000, nt4 returns 0xffffffff */
+ r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
+ ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
+
+ r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 ));
+ ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
+
+ r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 ));
+ ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
+
+ id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
+ ok( id == 0, "item id wrong\n");
+ id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi1");
+ ok( id == 1, "item id wrong\n");
+
+ r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
+ ok( r == 0x1, "ret %x\n", r );
+
+ r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 ));
+ ok( r == 0x10001, "ret %x\n", r );
+
+ /* Resize control so that below assertions about sizes are valid */
+ r = SendMessageA( hList, LB_GETITEMRECT, 0, (LPARAM)&rc);
+ ok( r == 1, "ret %x\n", r);
+ r = MoveWindow(hList, 1, 1, 600, (rc.bottom - rc.top + 1) * 9 / 2, TRUE);
+ ok( r != 0, "ret %x\n", r);
+
+ id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi2");
+ ok( id == 2, "item id wrong\n");
+ id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi3");
+ ok( id == 3, "item id wrong\n");
+ id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi4");
+ ok( id == 4, "item id wrong\n");
+ id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi5");
+ ok( id == 5, "item id wrong\n");
+ id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi6");
+ ok( id == 6, "item id wrong\n");
+ id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi7");
+ ok( id == 7, "item id wrong\n");
+
+ /* Set the listbox up so that id 1 is at the top, this leaves 5
+ partially visible at the bottom and 6, 7 are invisible */
+
+ SendMessageA( hList, LB_SETTOPINDEX, 1, 0);
+ r = SendMessageA( hList, LB_GETTOPINDEX, 0, 0);
+ ok( r == 1, "top %d\n", r);
+
+ r = SendMessageA( hList, LB_GETITEMRECT, 5, (LPARAM)&rc);
+ ok( r == 1, "ret %x\n", r);
+ r = SendMessageA( hList, LB_GETITEMRECT, 6, (LPARAM)&rc);
+ ok( r == 0, "ret %x\n", r);
+
+ r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(/* x */ 10, /* y */ 10) );
+ ok( r == 1, "ret %x\n", r);
+
+ r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) );
+ ok( r == 0x10001, "ret %x\n", r );
+
+ r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) );
+ ok( r == 0x10001, "ret %x\n", r );
+
+ r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) );
+ ok( r == 0x10005, "item %x\n", r );
+
+ r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) );
+ ok( r == 0x10005, "item %x\n", r );
+
+ DestroyWindow( hList );
+}
+
+static void test_listbox_item_data(void)
+{
+ HWND hList;
+ int r, id;
+
+ hList = CreateWindowA( "ListBox", "list test", 0,
+ 1, 1, 600, 100, NULL, NULL, NULL, NULL );
+ ok( hList != NULL, "failed to create listbox\n");
+
+ id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
+ ok( id == 0, "item id wrong\n");
+
+ r = SendMessageA( hList, LB_SETITEMDATA, 0, MAKELPARAM( 20, 0 ));
+ ok(r == TRUE, "LB_SETITEMDATA returned %d instead of TRUE\n", r);
+
+ r = SendMessageA( hList, LB_GETITEMDATA, 0, 0);
+ ok( r == 20, "get item data failed\n");
+
+ DestroyWindow( hList );
+}
+
+static void test_listbox_LB_DIR(void)
+{
+ HWND hList;
+ int res, itemCount;
+ int itemCount_justFiles;
+ int itemCount_justDrives;
+ int itemCount_allFiles;
+ int itemCount_allDirs;
+ int i;
+ char pathBuffer[MAX_PATH];
+ char * p;
+ char driveletter;
+ const char *wildcard = "*";
+ HANDLE file;
+
+ 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());
+ CloseHandle( file );
+
+ /* NOTE: for this test to succeed, there must be no subdirectories
+ under the current directory. In addition, there must be at least
+ one file that fits the wildcard w*.c . Normally, the test
+ directory itself satisfies both conditions.
+ */
+ hList = CreateWindowA( "ListBox", "list test", WS_VISIBLE|WS_POPUP,
+ 1, 1, 600, 100, NULL, NULL, NULL, NULL );
+ assert(hList);
+
+ /* Test for standard usage */
+
+ /* This should list all the files in the test directory. */
+ strcpy(pathBuffer, wildcard);
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
+ if (res == -1) /* "*" wildcard doesn't work on win9x */
+ {
+ wildcard = "*.*";
+ strcpy(pathBuffer, wildcard);
+ res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
+ }
+ ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError());
+
+ /* There should be some content in the listbox */
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
+ itemCount_allFiles = itemCount;
+ ok(res + 1 == itemCount,
+ "SendMessage(LB_DIR, 0, *) returned incorrect index (expected %d got %d)!\n",
+ itemCount - 1, res);
+
+ /* This tests behavior when no files match the wildcard */
+ strcpy(pathBuffer, BAD_EXTENSION);
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
+ ok (res == -1, "SendMessage(LB_DIR, 0, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
+
+ /* There should be NO content in the listbox */
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
+
+
+ /* This should list all the w*.c files in the test directory
+ * As of this writing, this includes win.c, winstation.c, wsprintf.c
+ */
+ strcpy(pathBuffer, "w*.c");
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
+ ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08x\n", GetLastError());
+
+ /* Path specification does NOT converted to uppercase */
+ ok (!strcmp(pathBuffer, "w*.c"),
+ "expected no change to pathBuffer, got %s\n", pathBuffer);
+
+ /* There should be some content in the listbox */
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
+ itemCount_justFiles = itemCount;
+ ok(res + 1 == itemCount,
+ "SendMessage(LB_DIR, 0, w*.c) returned incorrect index (expected %d got %d)!\n",
+ itemCount - 1, res);
+
+ /* Every single item in the control should start with a w and end in .c */
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
+ p = pathBuffer + strlen(pathBuffer);
+ ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
+ (*(p-1) == 'c' || *(p-1) == 'C') &&
+ (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
+ }
+
+ /* Test DDL_DIRECTORY */
+ strcpy(pathBuffer, wildcard);
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
+ ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError());
+
+ /* There should be some content in the listbox.
+ * All files plus "[..]"
+ */
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ itemCount_allDirs = itemCount - itemCount_allFiles;
+ ok (itemCount >= itemCount_allFiles,
+ "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected > %d\n",
+ itemCount, itemCount_allFiles);
+ ok(res + 1 == itemCount,
+ "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n",
+ itemCount - 1, res);
+
+ /* This tests behavior when no files match the wildcard */
+ strcpy(pathBuffer, BAD_EXTENSION);
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
+ ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
+
+ /* There should be NO content in the listbox */
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
+
+ /* Test DDL_DIRECTORY */
+ strcpy(pathBuffer, "w*.c");
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
+ ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08x\n", GetLastError());
+
+ /* There should be some content in the listbox. Since the parent directory does not
+ * fit w*.c, there should be exactly the same number of items as without DDL_DIRECTORY
+ */
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_justFiles,
+ "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) filled with %d entries, expected %d\n",
+ itemCount, itemCount_justFiles);
+ ok(res + 1 == itemCount,
+ "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) returned incorrect index (expected %d got %d)!\n",
+ itemCount - 1, res);
+
+ /* Every single item in the control should start with a w and end in .c. */
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
+ p = pathBuffer + strlen(pathBuffer);
+ ok(
+ ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
+ (*(p-1) == 'c' || *(p-1) == 'C') &&
+ (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
+ }
+
+ /* Test DDL_DRIVES|DDL_EXCLUSIVE */
+ strcpy(pathBuffer, wildcard);
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
+ ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError());
+
+ /* There should be some content in the listbox. In particular, there should
+ * be at least one element before, since the string "[-c-]" should
+ * have been added. Depending on the user setting, more drives might have
+ * been added.
+ */
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount >= 1,
+ "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) filled with %d entries, expected at least %d\n",
+ itemCount, 1);
+ itemCount_justDrives = itemCount;
+ ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) returned incorrect index!\n");
+
+ /* Every single item in the control should fit the format [-c-] */
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ driveletter = '\0';
+ SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
+ ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
+ ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
+ ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
+ if (!(driveletter >= 'a' && driveletter <= 'z'))
+ {
+ /* Correct after invalid entry is found */
+ itemCount_justDrives--;
+ }
+ }
+
+ /* This tests behavior when no files match the wildcard */
+ strcpy(pathBuffer, BAD_EXTENSION);
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
+ ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
+ BAD_EXTENSION, res, itemCount_justDrives -1);
+
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_justDrives, "SendMessage(LB_DIR) returned %d expected %d\n",
+ itemCount, itemCount_justDrives);
+
+ /* Test DDL_DRIVES. */
+ strcpy(pathBuffer, wildcard);
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
+ ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
+
+ /* There should be some content in the listbox. In particular, there should
+ * be at least one element before, since the string "[-c-]" should
+ * have been added. Depending on the user setting, more drives might have
+ * been added.
+ */
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_justDrives + itemCount_allFiles,
+ "SendMessage(LB_DIR, DDL_DRIVES, *) filled with %d entries, expected %d\n",
+ itemCount, itemCount_justDrives + itemCount_allFiles);
+ ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, *) returned incorrect index!\n");
+
+ /* This tests behavior when no files match the wildcard */
+ strcpy(pathBuffer, BAD_EXTENSION);
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
+ ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES, %s) returned %d, expected %d\n",
+ BAD_EXTENSION, res, itemCount_justDrives -1);
+
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
+
+ /* Test DDL_DRIVES. */
+ strcpy(pathBuffer, "w*.c");
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
+ ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
+
+ /* There should be some content in the listbox. In particular, there should
+ * be at least one element before, since the string "[-c-]" should
+ * have been added. Depending on the user setting, more drives might have
+ * been added.
+ */
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_justDrives + itemCount_justFiles,
+ "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n",
+ itemCount, itemCount_justDrives + itemCount_justFiles);
+ ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n");
+
+ /* Every single item in the control should fit the format [-c-], or w*.c */
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ driveletter = '\0';
+ SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
+ p = pathBuffer + strlen(pathBuffer);
+ if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
+ {
+ ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
+ ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
+ }
+ else
+ {
+ ok(
+ ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
+ (*(p-1) == 'c' || *(p-1) == 'C') &&
+ (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
+ }
+ }
+
+ /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
+ strcpy(pathBuffer, wildcard);
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
+ ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
+
+ /* There should be some content in the listbox. In particular, there should
+ * be exactly the number of plain files, plus the number of mapped drives.
+ */
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_allFiles + itemCount_justDrives + itemCount_allDirs,
+ "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
+ itemCount, itemCount_allFiles + itemCount_justDrives + itemCount_allDirs);
+ ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
+
+ /* Every single item in the control should start with a w and end in .c,
+ * except for the "[..]" string, which should appear exactly as it is,
+ * and the mapped drives in the format "[-X-]".
+ */
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ driveletter = '\0';
+ SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
+ if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
+ ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
+ }
+
+ /* This tests behavior when no files match the wildcard */
+ strcpy(pathBuffer, BAD_EXTENSION);
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
+ ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, %s) returned %d, expected %d\n",
+ BAD_EXTENSION, res, itemCount_justDrives -1);
+
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
+
+ /* Test DDL_DIRECTORY|DDL_DRIVES. */
+ strcpy(pathBuffer, "w*.c");
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
+ ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
+
+ /* There should be some content in the listbox. In particular, there should
+ * be exactly the number of plain files, plus the number of mapped drives.
+ */
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_justFiles + itemCount_justDrives,
+ "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
+ itemCount, itemCount_justFiles + itemCount_justDrives);
+ ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
+
+ /* Every single item in the control should start with a w and end in .c,
+ * except the mapped drives in the format "[-X-]". The "[..]" directory
+ * should not appear.
+ */
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ driveletter = '\0';
+ SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
+ p = pathBuffer + strlen(pathBuffer);
+ if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
+ ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
+ else
+ ok(
+ ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
+ (*(p-1) == 'c' || *(p-1) == 'C') &&
+ (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
+ }
+
+ /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
+ strcpy(pathBuffer, wildcard);
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
+ ok (res != -1 || broken(res == -1), "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %u\n",
+ GetLastError());
+
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_allDirs,
+ "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
+ 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 */
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ SendMessageA(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
+ ok( !strcmp(pathBuffer, "[..]"), "First element is not [..]\n");
+ }
+
+ /* This tests behavior when no files match the wildcard */
+ strcpy(pathBuffer, BAD_EXTENSION);
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
+ ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
+ BAD_EXTENSION, res, -1);
+
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
+
+
+ /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
+ strcpy(pathBuffer, "w*.c");
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
+ ok (res == LB_ERR, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, w*.c) returned %d expected %d\n", res, LB_ERR);
+
+ /* There should be no elements, since "[..]" does not fit w*.c */
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == 0,
+ "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
+ itemCount, 0);
+
+ /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
+ strcpy(pathBuffer, wildcard);
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
+ ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
+
+ /* There should be no plain files on the listbox */
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_justDrives + itemCount_allDirs,
+ "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
+ itemCount, itemCount_justDrives + itemCount_allDirs);
+ ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
+
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ driveletter = '\0';
+ SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
+ if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
+ ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
+ else
+ ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
+ "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
+ }
+
+ /* This tests behavior when no files match the wildcard */
+ strcpy(pathBuffer, BAD_EXTENSION);
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
+ ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
+ BAD_EXTENSION, res, itemCount_justDrives -1);
+
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
+
+ /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
+ strcpy(pathBuffer, "w*.c");
+ SendMessageA(hList, LB_RESETCONTENT, 0, 0);
+ res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
+ ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
+
+ /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */
+ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_justDrives,
+ "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
+ itemCount, itemCount_justDrives);
+ ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
+
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ driveletter = '\0';
+ SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
+ ok (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
+ ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
+ }
+ DestroyWindow(hList);
+
+ DeleteFileA( "wtest1.tmp.c" );
+}
+
+static HWND g_listBox;
+static HWND g_label;
+
+#define ID_TEST_LABEL 1001
+#define ID_TEST_LISTBOX 1002
+
+static BOOL on_listbox_container_create(HWND hwnd, CREATESTRUCTA *lpcs)
+{
+ g_label = CreateWindowA("Static", "Contents of static control before DlgDirList.",
+ WS_CHILD | WS_VISIBLE, 10, 10, 512, 32, hwnd, (HMENU)ID_TEST_LABEL, NULL, 0);
+ if (!g_label) return FALSE;
+
+ g_listBox = CreateWindowA("ListBox", "DlgDirList test",
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_VSCROLL, 10, 60, 256, 256,
+ hwnd, (HMENU)ID_TEST_LISTBOX, NULL, 0);
+ if (!g_listBox) return FALSE;
+
+ return TRUE;
+}
+
+static LRESULT CALLBACK listbox_container_window_procA(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT result = 0;
+
+ switch (uiMsg)
+ {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ case WM_CREATE:
+ result = on_listbox_container_create(hwnd, (CREATESTRUCTA *)lParam) ? 0 : (LRESULT)-1;
+ break;
+ default:
+ result = DefWindowProcA(hwnd, uiMsg, wParam, lParam);
+ break;
+ }
+ return result;
+}
+
+static BOOL RegisterListboxWindowClass(HINSTANCE hInst)
+{
+ WNDCLASSA cls;
+
+ cls.style = 0;
+ cls.cbClsExtra = 0;
+ cls.cbWndExtra = 0;
+ cls.hInstance = hInst;
+ cls.hIcon = NULL;
+ cls.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
+ cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ cls.lpszMenuName = NULL;
+ cls.lpfnWndProc = listbox_container_window_procA;
+ cls.lpszClassName = "ListboxContainerClass";
+ if (!RegisterClassA (&cls)) return FALSE;
+
+ return TRUE;
+}
+
+static void test_listbox_dlgdir(void)
+{
+ HINSTANCE hInst;
+ HWND hWnd;
+ int res, itemCount;
+ int itemCount_allDirs;
+ int itemCount_justFiles;
+ int itemCount_justDrives;
+ int i;
+ char pathBuffer[MAX_PATH];
+ char itemBuffer[MAX_PATH];
+ char tempBuffer[MAX_PATH];
+ char * p;
+ char driveletter;
+ HANDLE file;
+
+ 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());
+ CloseHandle( file );
+
+ /* NOTE: for this test to succeed, there must be no subdirectories
+ under the current directory. In addition, there must be at least
+ one file that fits the wildcard w*.c . Normally, the test
+ directory itself satisfies both conditions.
+ */
+
+ hInst = GetModuleHandleA(0);
+ if (!RegisterListboxWindowClass(hInst)) assert(0);
+
+ hWnd = CreateWindowA("ListboxContainerClass", "ListboxContainerClass",
+ WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ NULL, NULL, hInst, 0);
+ ok(hWnd != NULL, "Failed to create container window.\n");
+
+ /* Test for standard usage */
+
+ /* The following should be overwritten by the directory path */
+ SendMessageA(g_label, WM_SETTEXT, 0, (LPARAM)"default contents");
+
+ /* This should list all the w*.c files in the test directory
+ * As of this writing, this includes win.c, winstation.c, wsprintf.c
+ */
+ strcpy(pathBuffer, "w*.c");
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
+ ok (res == 1, "DlgDirList(*.c, 0) returned %d - expected 1 - 0x%08x\n", res, GetLastError());
+
+ /* Path specification gets converted to uppercase */
+ ok (!strcmp(pathBuffer, "W*.C"),
+ "expected conversion to uppercase, got %s\n", pathBuffer);
+
+ /* Loaded path should have overwritten the label text */
+ SendMessageA(g_label, WM_GETTEXT, MAX_PATH, (LPARAM)pathBuffer);
+ ok (strcmp("default contents", pathBuffer), "DlgDirList() did not modify static control!\n");
+
+ /* There should be some content in the listbox */
+ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
+ ok (itemCount > 0, "DlgDirList() did NOT fill the listbox!\n");
+ itemCount_justFiles = itemCount;
+
+ /* Every single item in the control should start with a w and end in .c */
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
+ p = pathBuffer + strlen(pathBuffer);
+ ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
+ (*(p-1) == 'c' || *(p-1) == 'C') &&
+ (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
+ }
+
+ /* Test behavior when no files match the wildcard */
+ strcpy(pathBuffer, BAD_EXTENSION);
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
+ ok (res == 1, "DlgDirList(%s, 0) returned %d expected 1\n", BAD_EXTENSION, res);
+
+ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
+ ok (itemCount == 0, "DlgDirList() DID fill the listbox!\n");
+
+ /* Test DDL_DIRECTORY */
+ strcpy(pathBuffer, "w*.c");
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY);
+ ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError());
+
+ /* There should be some content in the listbox. In particular, there should
+ * be exactly more elements than before, since the directories should
+ * have been added.
+ */
+ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
+ itemCount_allDirs = itemCount - itemCount_justFiles;
+ ok (itemCount >= itemCount_justFiles, "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected > %d\n",
+ itemCount, itemCount_justFiles);
+
+ /* Every single item in the control should start with a w and end in .c,
+ * except for the "[..]" string, which should appear exactly as it is.
+ */
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
+ p = pathBuffer + strlen(pathBuffer);
+ ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
+ ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
+ (*(p-1) == 'c' || *(p-1) == 'C') &&
+ (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
+ }
+
+ /* Test behavior when no files match the wildcard */
+ strcpy(pathBuffer, BAD_EXTENSION);
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY);
+ ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY) returned %d expected 1\n", BAD_EXTENSION, res);
+
+ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
+ itemCount_allDirs, itemCount);
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
+ ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
+ "Element %d (%s) does not fit requested [...]\n", i, pathBuffer);
+ }
+
+ /* Test DDL_DRIVES. At least on WinXP-SP2, this implies DDL_EXCLUSIVE */
+ strcpy(pathBuffer, "w*.c");
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DRIVES);
+ ok (res == 1, "DlgDirList(*.c, DDL_DRIVES) failed - 0x%08x\n", GetLastError());
+
+ /* There should be some content in the listbox. In particular, there should
+ * be at least one element before, since the string "[-c-]" should
+ * have been added. Depending on the user setting, more drives might have
+ * been added.
+ */
+ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
+ ok (itemCount >= 1,
+ "DlgDirList(DDL_DRIVES) filled with %d entries, expected at least %d\n",
+ itemCount, 1);
+ itemCount_justDrives = itemCount;
+
+ /* Every single item in the control should fit the format [-c-] */
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ driveletter = '\0';
+ SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
+ ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
+ ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
+ ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
+ if (!(driveletter >= 'a' && driveletter <= 'z')) {
+ /* Correct after invalid entry is found */
+ trace("removing count of invalid entry %s\n", pathBuffer);
+ itemCount_justDrives--;
+ }
+ }
+
+ /* Test behavior when no files match the wildcard */
+ strcpy(pathBuffer, BAD_EXTENSION);
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DRIVES);
+ ok (res == 1, "DlgDirList(%s, DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
+
+ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_justDrives, "DlgDirList() incorrectly filled the listbox!\n");
+
+ /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
+ strcpy(pathBuffer, "w*.c");
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
+ ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
+
+ /* There should be some content in the listbox. In particular, there should
+ * be exactly the number of plain files, plus the number of mapped drives,
+ * plus one "[..]"
+ */
+ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_justFiles + itemCount_justDrives + itemCount_allDirs,
+ "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
+ itemCount, itemCount_justFiles + itemCount_justDrives + itemCount_allDirs);
+
+ /* Every single item in the control should start with a w and end in .c,
+ * except for the "[..]" string, which should appear exactly as it is,
+ * and the mapped drives in the format "[-X-]".
+ */
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ driveletter = '\0';
+ SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
+ p = pathBuffer + strlen(pathBuffer);
+ if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
+ ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
+ else
+ ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
+ ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
+ (*(p-1) == 'c' || *(p-1) == 'C') &&
+ (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
+ }
+
+ /* Test behavior when no files match the wildcard */
+ strcpy(pathBuffer, BAD_EXTENSION);
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
+ ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
+
+ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_justDrives + itemCount_allDirs,
+ "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
+ itemCount_justDrives + itemCount_allDirs, itemCount);
+
+ /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
+ strcpy(pathBuffer, "w*.c");
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_EXCLUSIVE);
+ ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
+
+ /* There should be exactly one element: "[..]" */
+ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_allDirs,
+ "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
+ itemCount, itemCount_allDirs);
+
+ if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ SendMessageA(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer);
+ ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
+ }
+
+ /* Test behavior when no files match the wildcard */
+ strcpy(pathBuffer, BAD_EXTENSION);
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_EXCLUSIVE);
+ ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
+
+ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
+
+ /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
+ strcpy(pathBuffer, "w*.c");
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
+ ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
+
+ /* There should be no plain files on the listbox */
+ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_justDrives + itemCount_allDirs,
+ "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
+ itemCount, itemCount_justDrives + itemCount_allDirs);
+
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(pathBuffer, 0, MAX_PATH);
+ driveletter = '\0';
+ SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
+ if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
+ ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
+ else
+ ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
+ "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
+ }
+
+ /* Test behavior when no files match the wildcard */
+ strcpy(pathBuffer, BAD_EXTENSION);
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
+ ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
+
+ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
+ ok (itemCount == itemCount_justDrives + itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
+
+ /* Now test DlgDirSelectEx() in normal operation */
+ /* Fill with everything - drives, directory and all plain files. */
+ strcpy(pathBuffer, "*");
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
+ ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
+
+ SendMessageA(g_listBox, LB_SETCURSEL, -1, 0); /* Unselect any current selection */
+ memset(pathBuffer, 0, MAX_PATH);
+ SetLastError(0xdeadbeef);
+ res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
+ ok (GetLastError() == 0xdeadbeef,
+ "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08x\n",
+ GetLastError());
+ ok (res == 0, "DlgDirSelectEx() with no selection returned %d, expected 0\n", res);
+ /* WinXP-SP2 leaves pathBuffer untouched, but Win98 fills it with garbage. */
+ /*
+ ok (strlen(pathBuffer) == 0, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer);
+ */
+ /* Test proper drive/dir/file recognition */
+ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(itemBuffer, 0, MAX_PATH);
+ memset(pathBuffer, 0, MAX_PATH);
+ memset(tempBuffer, 0, MAX_PATH);
+ driveletter = '\0';
+ SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
+ res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
+ ok (res == i, "SendMessageA(LB_SETCURSEL, %d) failed\n", i);
+ if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1)
+ {
+ /* Current item is a drive letter */
+ SetLastError(0xdeadbeef);
+ res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
+ ok (GetLastError() == 0xdeadbeef,
+ "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
+ i, GetLastError());
+ ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
+
+ /* For drive letters, DlgDirSelectEx tacks on a colon */
+ ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
+ "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
+ }
+ else if (itemBuffer[0] == '[')
+ {
+ /* Current item is the parent directory */
+ SetLastError(0xdeadbeef);
+ res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
+ ok (GetLastError() == 0xdeadbeef,
+ "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
+ i, GetLastError());
+ ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
+
+ /* For directories, DlgDirSelectEx tacks on a backslash */
+ p = pathBuffer + strlen(pathBuffer);
+ ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
+
+ tempBuffer[0] = '[';
+ lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
+ strcat(tempBuffer, "]");
+ ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
+ }
+ else
+ {
+ /* Current item is a plain file */
+ SetLastError(0xdeadbeef);
+ res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
+ ok (GetLastError() == 0xdeadbeef,
+ "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
+ i, GetLastError());
+ ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
+
+ /* NOTE: WinXP tacks a period on all files that lack an extension. This affects
+ * for example, "Makefile", which gets reported as "Makefile."
+ */
+ strcpy(tempBuffer, itemBuffer);
+ if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
+ ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
+ }
+ }
+
+ DeleteFileA( "wtest1.tmp.c" );
+
+ /* Now test DlgDirSelectEx() in abnormal operation */
+ /* Fill list with bogus entries, that look somewhat valid */
+ SendMessageA(g_listBox, LB_RESETCONTENT, 0, 0);
+ SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"[notexist.dir]");
+ SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"notexist.fil");
+ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
+ for (i = 0; i < itemCount; i++)
+ {
+ memset(itemBuffer, 0, MAX_PATH);
+ memset(pathBuffer, 0, MAX_PATH);
+ memset(tempBuffer, 0, MAX_PATH);
+ driveletter = '\0';
+ SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
+ res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
+ ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i);
+ if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1)
+ {
+ /* Current item is a drive letter */
+ SetLastError(0xdeadbeef);
+ res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
+ ok (GetLastError() == 0xdeadbeef,
+ "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
+ i, GetLastError());
+ ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
+
+ /* For drive letters, DlgDirSelectEx tacks on a colon */
+ ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
+ "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
+ }
+ else if (itemBuffer[0] == '[')
+ {
+ /* Current item is the parent directory */
+ SetLastError(0xdeadbeef);
+ res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
+ ok (GetLastError() == 0xdeadbeef,
+ "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
+ i, GetLastError());
+ ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
+
+ /* For directories, DlgDirSelectEx tacks on a backslash */
+ p = pathBuffer + strlen(pathBuffer);
+ ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
+
+ tempBuffer[0] = '[';
+ lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
+ strcat(tempBuffer, "]");
+ ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
+ }
+ else
+ {
+ /* Current item is a plain file */
+ SetLastError(0xdeadbeef);
+ res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
+ ok (GetLastError() == 0xdeadbeef,
+ "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
+ i, GetLastError());
+ ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
+
+ /* NOTE: WinXP and Win98 tack a period on all files that lack an extension.
+ * This affects for example, "Makefile", which gets reported as "Makefile."
+ */
+ strcpy(tempBuffer, itemBuffer);
+ if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
+ ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
+ }
+ }
+
+ /* Test behavior when loading folders from root with and without wildcard */
+ strcpy(pathBuffer, "C:\\");
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
+ ok(res, "DlgDirList failed to list C:\\ folders\n");
+ todo_wine ok(!strcmp(pathBuffer, "*"), "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
+
+ strcpy(pathBuffer, "C:\\*");
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
+ ok(res, "DlgDirList failed to list C:\\* folders\n");
+ ok(!strcmp(pathBuffer, "*"), "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
+
+ /* Try loading files from an invalid folder */
+ SetLastError(0xdeadbeef);
+ strcpy(pathBuffer, "C:\\INVALID$$DIR");
+ res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
+ todo_wine ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res);
+ todo_wine ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS,
+ "GetLastError should return 0x589, got 0x%X\n",GetLastError());
+
+ 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 = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
+ ok( ret == 0, "got %d\n", ret );
+ ret = SendMessageA( 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 = SendMessageA( 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 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;
+
+ 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 = GetListBoxInfo(listbox);
+ ok(ret > 0, "got %d\n", ret);
+ ok(lb_getlistboxinfo == 1, "got %d\n", lb_getlistboxinfo);
+
+ DestroyWindow(listbox);
+ DestroyWindow(parent);
+}
+
+static void test_missing_lbuttonup(void)
+{
+ HWND listbox, parent, capture;
+
+ parent = create_parent();
+ listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
+
+ /* Send button down without a corresponding button up */
+ SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(10, 10));
+ capture = GetCapture();
+ ok(capture == listbox, "got %p expected %p\n", capture, listbox);
+
+ /* Capture is released and LBN_SELCHANGE sent during WM_KILLFOCUS */
+ got_selchange = 0;
+ SetFocus(NULL);
+ capture = GetCapture();
+ ok(capture == NULL, "got %p\n", capture);
+ ok(got_selchange, "got %d\n", got_selchange);
+
+ DestroyWindow(listbox);
+ DestroyWindow(parent);
+}
+
+static void test_extents(void)
+{
+ HWND listbox, parent;
+ SCROLLINFO sinfo;
+ DWORD res;
+ BOOL br;
+
+ parent = create_parent();
+
+ listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
+
+ res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
+ ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
+
+ sinfo.cbSize = sizeof(sinfo);
+ sinfo.fMask = SIF_RANGE;
+ br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
+ ok(br == TRUE, "GetScrollInfo failed\n");
+ ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
+ ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
+ ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
+ "List box should not have a horizontal scroll bar\n");
+
+ /* horizontal extent < width */
+ SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
+
+ res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
+ ok(res == 64, "Got wrong horizontal extent: %u\n", res);
+
+ sinfo.cbSize = sizeof(sinfo);
+ sinfo.fMask = SIF_RANGE;
+ br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
+ ok(br == TRUE, "GetScrollInfo failed\n");
+ ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
+ ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
+ ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
+ "List box should not have a horizontal scroll bar\n");
+
+ /* horizontal extent > width */
+ SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
+
+ res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
+ ok(res == 184, "Got wrong horizontal extent: %u\n", res);
+
+ sinfo.cbSize = sizeof(sinfo);
+ sinfo.fMask = SIF_RANGE;
+ br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
+ ok(br == TRUE, "GetScrollInfo failed\n");
+ ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
+ ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
+ ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
+ "List box should not have a horizontal scroll bar\n");
+
+ DestroyWindow(listbox);
+
+ listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL, parent);
+
+ res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
+ ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
+
+ sinfo.cbSize = sizeof(sinfo);
+ sinfo.fMask = SIF_RANGE;
+ br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
+ ok(br == TRUE, "GetScrollInfo failed\n");
+ ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
+ ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
+ ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
+ "List box should not have a horizontal scroll bar\n");
+
+ /* horizontal extent < width */
+ SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
+
+ res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
+ ok(res == 64, "Got wrong horizontal extent: %u\n", res);
+
+ sinfo.cbSize = sizeof(sinfo);
+ sinfo.fMask = SIF_RANGE;
+ br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
+ ok(br == TRUE, "GetScrollInfo failed\n");
+ ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
+ ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
+ ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
+ "List box should not have a horizontal scroll bar\n");
+
+ /* horizontal extent > width */
+ SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
+
+ res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
+ ok(res == 184, "Got wrong horizontal extent: %u\n", res);
+
+ sinfo.cbSize = sizeof(sinfo);
+ sinfo.fMask = SIF_RANGE;
+ br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
+ ok(br == TRUE, "GetScrollInfo failed\n");
+ ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
+ ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
+ ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
+ "List box should have a horizontal scroll bar\n");
+
+ SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
+
+ res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
+ ok(res == 0, "Got wrong horizontal extent: %u\n", res);
+
+ sinfo.cbSize = sizeof(sinfo);
+ sinfo.fMask = SIF_RANGE;
+ br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
+ ok(br == TRUE, "GetScrollInfo failed\n");
+ ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
+ ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
+ ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
+ "List box should not have a horizontal scroll bar\n");
+
+ DestroyWindow(listbox);
+
+
+ listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL | LBS_DISABLENOSCROLL, parent);
+
+ res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
+ ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
+
+ sinfo.cbSize = sizeof(sinfo);
+ sinfo.fMask = SIF_RANGE;
+ br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
+ ok(br == TRUE, "GetScrollInfo failed\n");
+ ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
+ ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
+ ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
+ "List box should have a horizontal scroll bar\n");
+
+ /* horizontal extent < width */
+ SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
+
+ res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
+ ok(res == 64, "Got wrong horizontal extent: %u\n", res);
+
+ sinfo.cbSize = sizeof(sinfo);
+ sinfo.fMask = SIF_RANGE;
+ br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
+ ok(br == TRUE, "GetScrollInfo failed\n");
+ ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
+ ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
+ ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
+ "List box should have a horizontal scroll bar\n");
+
+ /* horizontal extent > width */
+ SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
+
+ res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
+ ok(res == 184, "Got wrong horizontal extent: %u\n", res);
+
+ sinfo.cbSize = sizeof(sinfo);
+ sinfo.fMask = SIF_RANGE;
+ br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
+ ok(br == TRUE, "GetScrollInfo failed\n");
+ ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
+ ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
+ ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
+ "List box should have a horizontal scroll bar\n");
+
+ SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
+
+ res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
+ ok(res == 0, "Got wrong horizontal extent: %u\n", res);
+
+ sinfo.cbSize = sizeof(sinfo);
+ sinfo.fMask = SIF_RANGE;
+ br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
+ ok(br == TRUE, "GetScrollInfo failed\n");
+ ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
+ ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
+ ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
+ "List box should have a horizontal scroll bar\n");
+
+ DestroyWindow(listbox);
+
+ DestroyWindow(parent);
+}
+
+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},
+ { 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},
+ { 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},
+ { 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},
+ { 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},
+ { 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},
+ { 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},
+ { 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},
+ { 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);
+}
+
+START_TEST(listbox)
+{
+ ULONG_PTR ctx_cookie;
+ HANDLE hCtx;
+
+ if (!load_v6_module(&ctx_cookie, &hCtx))
+ return;
+
+ test_listbox();
+ test_item_height();
+ test_ownerdraw();
+ test_LB_SELITEMRANGE();
+ test_LB_SETCURSEL();
+ test_listbox_height();
+ test_itemfrompoint();
+ test_listbox_item_data();
+ test_listbox_LB_DIR();
+ test_listbox_dlgdir();
+ test_set_count();
+ test_GetListBoxInfo();
+ test_missing_lbuttonup();
+ test_extents();
+
+ unload_v6_module(ctx_cookie, hCtx);
+}
{ 0 }
};
+static const struct message parent_focus_change_ownerdata_seq[] = {
+ { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
+ { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
+ { 0 }
+};
+
static const struct message forward_erasebkgnd_parent_seq[] = {
{ WM_ERASEBKGND, sent },
{ 0 }
LRESULT ret;
struct message msg;
- /* 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;
static void test_create(void)
{
+ static const WCHAR testtextW[] = {'t','e','s','t',' ','t','e','x','t',0};
+ char buff[16];
HWND hList;
HWND hHeader;
LONG_PTR ret;
hList = CreateWindowA("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
ok((HIMAGELIST)SendMessageA(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
-
- if (!IsWindow(hHeader))
- {
- /* version 4.0 */
- win_skip("LVM_GETHEADER not implemented. Skipping.\n");
- DestroyWindow(hList);
- return;
- }
-
ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
DestroyWindow(hList);
ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
"created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
DestroyWindow(hList);
+
+ /* Test that window text is preserved. */
+ hList = CreateWindowExA(0, WC_LISTVIEWA, "test text", WS_CHILD | WS_BORDER | WS_VISIBLE,
+ 0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
+ ok(hList != NULL, "Failed to create ListView window.\n");
+ *buff = 0;
+ GetWindowTextA(hList, buff, sizeof(buff));
+ ok(!strcmp(buff, "test text"), "Unexpected window text %s.\n", buff);
+ DestroyWindow(hList);
+
+ hList = CreateWindowExW(0, WC_LISTVIEWW, testtextW, WS_CHILD | WS_BORDER | WS_VISIBLE,
+ 0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
+ ok(hList != NULL, "Failed to create ListView window.\n");
+ *buff = 0;
+ GetWindowTextA(hList, buff, sizeof(buff));
+ ok(!strcmp(buff, "test text"), "Unexpected window text %s.\n", buff);
+ DestroyWindow(hList);
}
static void test_redraw(void)
clr = GetBkColor(nmlvcd->nmcd.hdc);
ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
- if (!(GetWindowLongW(nmhdr->hwndFrom, GWL_STYLE) & LVS_SHOWSELALWAYS))
- {
- todo_wine_if(nmlvcd->iSubItem)
- ok(clr == c0ffee, "clr=%.8x\n", clr);
- }
+ todo_wine_if(nmlvcd->iSubItem)
+ ok(clr == c0ffee, "clr=%.8x\n", clr);
return CDRF_NOTIFYPOSTPAINT;
case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
clr = GetBkColor(nmlvcd->nmcd.hdc);
- if (!(GetWindowLongW(nmhdr->hwndFrom, GWL_STYLE) & LVS_SHOWSELALWAYS))
- todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
+ todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
return CDRF_DODEFAULT;
{
HWND hwnd;
WNDPROC oldwndproc;
- LVITEMA item;
hwnd = create_listview_control(LVS_REPORT);
UpdateWindow(hwnd);
ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT", FALSE);
- /* check colors when item is selected */
- SetWindowLongW(hwnd, GWL_STYLE, GetWindowLongW(hwnd, GWL_STYLE) | LVS_SHOWSELALWAYS);
- item.mask = LVIF_STATE;
- item.stateMask = LVIS_SELECTED;
- item.state = LVIS_SELECTED;
- SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
-
- flush_sequences(sequences, NUM_MSG_SEQUENCES);
- InvalidateRect(hwnd, NULL, TRUE);
- UpdateWindow(hwnd);
- ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT, selection", FALSE);
-
DestroyWindow(hwnd);
hwnd = create_listview_control(LVS_LIST);
"Expected %d, got %d\n", MAKELONG(w, h), r);
r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
- if (r == 0)
- {
- /* version 4.0 */
- win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
- DestroyWindow(hwnd);
- return;
- }
expect(MAKELONG(20,30), r);
r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 1, 0);
expect(0, r);
r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
- if (r == 1)
- {
- r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
- expect(1, r);
- r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
- expect(0, r);
- }
- else
- {
- win_skip("LVM_GETUNICODEFORMAT is unsupported\n");
- DestroyWindow(hwnd);
- return;
- }
+ ok(r == 1, "Unexpected return value %d.\n", r);
+ r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
+ expect(1, r);
+ r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
+ expect(0, r);
DestroyWindow(hwnd);
static void test_approximate_viewrect(void)
{
- HWND hwnd;
- DWORD ret;
+ static CHAR test[] = "abracadabra, a very long item label";
+ DWORD item_width, item_height, header_height;
+ static CHAR column_header[] = "Header";
+ unsigned const column_width = 100;
+ DWORD ret, item_count;
HIMAGELIST himl;
- HBITMAP hbmp;
LVITEMA itema;
- static CHAR test[] = "abracadabra, a very long item label";
+ LVCOLUMNA col;
+ HBITMAP hbmp;
+ HWND hwnd;
+ /* LVS_ICON */
hwnd = create_listview_control(LVS_ICON);
himl = ImageList_Create(40, 40, 0, 4, 4);
ok(himl != NULL, "failed to create imagelist\n");
expect(0, ret);
ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(75, 75));
- if (ret == 0)
- {
- /* version 4.0 */
- win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
- return;
- }
+ ok(ret != 0, "Unexpected return value %#x.\n", ret);
ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
expect(MAKELONG(77,827), ret);
expect(MAKELONG(152,152), ret);
DestroyWindow(hwnd);
+
+ /* LVS_REPORT */
+ hwnd = create_listview_control(LVS_REPORT);
+
+ /* Empty control without columns */
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100, 100));
+todo_wine
+ ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
+ ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
+ ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
+todo_wine
+ ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
+
+ header_height = HIWORD(ret);
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
+ ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
+todo_wine
+ ok(HIWORD(ret) > header_height, "Unexpected height %d.\n", HIWORD(ret));
+
+ item_height = HIWORD(ret) - header_height;
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
+ ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
+ ok(HIWORD(ret) == (header_height - 2 * item_height), "Unexpected height %d.\n", HIWORD(ret)) ;
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
+ ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
+ ok(HIWORD(ret) == header_height, "Unexpected height.\n");
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
+ ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
+ ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
+
+ /* Insert column */
+ col.mask = LVCF_TEXT | LVCF_WIDTH;
+ col.pszText = column_header;
+ col.cx = column_width;
+ ret = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
+ ok(ret == 0, "Unexpected return value %d.\n", ret);
+
+ /* Empty control with column */
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
+todo_wine {
+ ok(LOWORD(ret) >= column_width, "Unexpected width %d.\n", LOWORD(ret));
+ ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
+}
+ header_height = HIWORD(ret);
+ item_width = LOWORD(ret);
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
+ ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
+todo_wine
+ ok(HIWORD(ret) > header_height, "Unexpected height %d.\n", HIWORD(ret));
+
+ item_height = HIWORD(ret) - header_height;
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
+ ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
+ ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
+ ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
+ ok(HIWORD(ret) == header_height, "Unexpected height %d.\n", HIWORD(ret));
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
+ ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
+ ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
+
+ for (item_count = 1; item_count <= 2; ++item_count)
+ {
+ itema.mask = LVIF_TEXT;
+ itema.iItem = 0;
+ itema.iSubItem = 0;
+ itema.pszText = test;
+ ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
+ ok(ret == 0, "Unexpected return value %d.\n", ret);
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
+ ok(LOWORD(ret) >= column_width, "Unexpected width %d.\n", LOWORD(ret));
+ todo_wine
+ ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
+
+ header_height = HIWORD(ret);
+ item_width = LOWORD(ret);
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
+ ok(LOWORD(ret) == item_width, "Unexpected width %d, item %d\n", LOWORD(ret), item_count - 1);
+ ok(HIWORD(ret) > header_height, "Unexpected height %d. item %d.\n", HIWORD(ret), item_count - 1);
+
+ item_height = HIWORD(ret) - header_height;
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
+ ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
+ todo_wine
+ ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
+ ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
+ ok(HIWORD(ret) == header_height + item_count * item_height, "Unexpected height %d.\n", HIWORD(ret));
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
+ ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
+ ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELONG(item_width * 2, header_height + 3 * item_height));
+ ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
+ ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, MAKELONG(item_width * 2, 0));
+ ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
+ todo_wine
+ ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
+
+ ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, MAKELONG(-1, -1));
+ ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
+ todo_wine
+ ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
+ }
+
+ DestroyWindow(hwnd);
+
}
static void test_finditem(void)
fi.flags = LVFI_SUBSTRING;
fi.psz = f;
r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
- if (r == -1)
- {
- win_skip("LVFI_SUBSTRING not supported\n");
- DestroyWindow(hwnd);
- return;
- }
expect(0, r);
strcpy(f, "f");
fi.flags = LVFI_SUBSTRING;
static void test_callback_mask(void)
{
+ LVITEMA item;
DWORD mask;
HWND hwnd;
BOOL ret;
ok(mask == ~0u, "got 0x%08x\n", mask);
DestroyWindow(hwnd);
+
+ /* LVS_OWNERDATA, mask LVIS_FOCUSED */
+ hwnd = create_listview_control(LVS_REPORT | LVS_OWNERDATA);
+
+ mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
+ ok(mask == 0, "Unexpected callback mask %#x.\n", mask);
+
+ ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_FOCUSED, 0);
+ ok(ret, "Failed to set callback mask, %d\n", ret);
+
+ mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
+ ok(mask == LVIS_FOCUSED, "Unexpected callback mask %#x.\n", mask);
+
+ ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
+ ok(ret, "Failed to set item count.\n");
+
+ ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+ ok(ret == -1, "Unexpected selection mark, %d\n", ret);
+
+ item.stateMask = LVIS_FOCUSED;
+ item.state = LVIS_FOCUSED;
+ ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
+ ok(ret, "Failed to set item state.\n");
+
+ flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+ ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
+todo_wine
+ ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
+
+ ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+todo_wine
+ ok(ret == 0, "Unexpected selection mark, %d\n", ret);
+
+ ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
+ ok(ret, "Failed to set item count.\n");
+
+ ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
+ ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
+
+ ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+ ok(ret == -1, "Unexpected selection mark, %d\n", ret);
+
+ ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
+ ok(ret, "Failed to set item count.\n");
+
+ ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
+ ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
+
+ ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent seq, owner data/focus 1", FALSE);
+
+ /* LVS_OWNDERDATA, empty mask */
+ ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, 0, 0);
+ ok(ret, "Failed to set callback mask, %d\n", ret);
+
+ ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
+ ok(ret, "Failed to set item count.\n");
+
+ ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+ ok(ret == -1, "Unexpected selection mark, %d\n", ret);
+
+ item.stateMask = LVIS_FOCUSED;
+ item.state = LVIS_FOCUSED;
+ ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
+ ok(ret, "Failed to set item state.\n");
+
+ ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+ ok(ret == 0, "Unexpected selection mark, %d\n", ret);
+
+ flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+ ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
+ ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
+
+ ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
+ ok(ret, "Failed to set item count.\n");
+
+ ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
+ ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
+
+ ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
+todo_wine
+ ok(ret == -1, "Unexpected selection mark, %d\n", ret);
+
+ ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
+ ok(ret, "Failed to set item count.\n");
+
+ ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
+ ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
+
+ ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent seq, owner data/focus 2", FALSE);
+
+ /* 2 items, focus on index 0, reduce to 1 item. */
+ flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+ ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 2, 0);
+ ok(ret, "Failed to set item count.\n");
+
+ ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
+ ok(ret, "Failed to set item state.\n");
+
+ ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
+ ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
+
+ ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
+ ok(ret, "Failed to set item count.\n");
+
+ ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
+ ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
+
+ ok_sequence(sequences, PARENT_SEQ_INDEX, parent_focus_change_ownerdata_seq,
+ "parent seq, owner data/focus 3", TRUE);
+
+ DestroyWindow(hwnd);
+}
+
+static void test_state_image(void)
+{
+ static const DWORD styles[] =
+ {
+ LVS_ICON,
+ LVS_REPORT,
+ LVS_SMALLICON,
+ LVS_LIST,
+ };
+ int i;
+
+ for (i = 0; i < sizeof(styles)/sizeof(styles[0]); i++)
+ {
+ static char text[] = "Item";
+ static char subtext[] = "Subitem";
+ char buff[16];
+ LVITEMA item;
+ HWND hwnd;
+ int r;
+
+ hwnd = create_listview_control(styles[i]);
+
+ insert_column(hwnd, 0);
+ insert_column(hwnd, 1);
+
+ item.mask = LVIF_TEXT;
+ item.iItem = 0;
+ item.iSubItem = 0;
+ item.pszText = text;
+ r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
+ ok(r == 0, "Failed to insert an item.\n");
+
+ item.mask = LVIF_STATE;
+ item.state = INDEXTOSTATEIMAGEMASK(1) | LVIS_SELECTED;
+ item.stateMask = LVIS_STATEIMAGEMASK | LVIS_SELECTED;
+ item.iItem = 0;
+ item.iSubItem = 0;
+ r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
+ ok(r, "Failed to set item state.\n");
+
+ item.mask = LVIF_TEXT;
+ item.iItem = 0;
+ item.iSubItem = 1;
+ item.pszText = subtext;
+ r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
+ ok(r, "Failed to set subitem text.\n");
+
+ item.mask = LVIF_STATE;
+ item.stateMask = LVIS_STATEIMAGEMASK | LVIS_SELECTED;
+ item.state = 0;
+ item.iItem = 0;
+ item.iSubItem = 0;
+ r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
+ ok(r, "Failed to get item state.\n");
+ ok(item.state == (INDEXTOSTATEIMAGEMASK(1) | LVIS_SELECTED), "Unexpected item state %#x.\n", item.state);
+
+ item.mask = LVIF_STATE;
+ item.stateMask = LVIS_STATEIMAGEMASK | LVIS_SELECTED;
+ item.state = INDEXTOSTATEIMAGEMASK(2);
+ item.iItem = 0;
+ item.iSubItem = 1;
+ r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
+ ok(r, "Failed to get subitem state.\n");
+ todo_wine
+ ok(item.state == 0, "Unexpected state %#x.\n", item.state);
+
+ item.mask = LVIF_STATE;
+ item.stateMask = LVIS_STATEIMAGEMASK | LVIS_SELECTED;
+ item.state = INDEXTOSTATEIMAGEMASK(2);
+ item.iItem = 0;
+ item.iSubItem = 2;
+ r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
+ ok(r, "Failed to get subitem state.\n");
+ todo_wine
+ ok(item.state == 0, "Unexpected state %#x.\n", item.state);
+
+ item.mask = LVIF_TEXT;
+ item.iItem = 0;
+ item.iSubItem = 1;
+ item.pszText = buff;
+ item.cchTextMax = sizeof(buff);
+ r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
+ ok(r, "Failed to get subitem text %d.\n", r);
+ ok(!strcmp(buff, subtext), "Unexpected subitem text %s.\n", buff);
+
+ DestroyWindow(hwnd);
+ }
}
START_TEST(listview)
test_header_proc();
test_oneclickactivate();
test_callback_mask();
+ test_state_image();
if (!load_v6_module(&ctx_cookie, &hCtx))
{
test_multiselect();
test_insertitem();
test_header_proc();
+