From af0423f839378efaa5af60e6b277eecc4f87be79 Mon Sep 17 00:00:00 2001 From: Steven Edwards Date: Sun, 7 Nov 2004 14:36:23 +0000 Subject: [PATCH] Added Wine Common Control Regression tests. As of 2004-10-7 we pass all of these tests. svn path=/trunk/; revision=11572 --- reactos/lib/comctl32/tests/.cvsignore | 5 + reactos/lib/comctl32/tests/Makefile | 30 ++ reactos/lib/comctl32/tests/dpa.c | 81 ++++ reactos/lib/comctl32/tests/imagelist.c | 560 +++++++++++++++++++++++++ reactos/lib/comctl32/tests/subclass.c | 298 +++++++++++++ reactos/lib/comctl32/tests/tab.c | 197 +++++++++ reactos/lib/comctl32/tests/testlist.c | 31 ++ 7 files changed, 1202 insertions(+) create mode 100644 reactos/lib/comctl32/tests/.cvsignore create mode 100644 reactos/lib/comctl32/tests/Makefile create mode 100644 reactos/lib/comctl32/tests/dpa.c create mode 100644 reactos/lib/comctl32/tests/imagelist.c create mode 100644 reactos/lib/comctl32/tests/subclass.c create mode 100644 reactos/lib/comctl32/tests/tab.c create mode 100644 reactos/lib/comctl32/tests/testlist.c diff --git a/reactos/lib/comctl32/tests/.cvsignore b/reactos/lib/comctl32/tests/.cvsignore new file mode 100644 index 00000000000..4214d70a7b6 --- /dev/null +++ b/reactos/lib/comctl32/tests/.cvsignore @@ -0,0 +1,5 @@ +*.o +*.a +*.exe +*.map +*.sym \ No newline at end of file diff --git a/reactos/lib/comctl32/tests/Makefile b/reactos/lib/comctl32/tests/Makefile new file mode 100644 index 00000000000..66e33be3586 --- /dev/null +++ b/reactos/lib/comctl32/tests/Makefile @@ -0,0 +1,30 @@ +# $Id: Makefile,v 1.1 2004/11/07 14:36:23 sedwards Exp $ + +PATH_TO_TOP = ../../.. + +TARGET_NORC = yes + +TARGET_TYPE = program + +TARGET_APPTYPE = console + +# require os code to explicitly request A/W version of structs/functions +TARGET_CFLAGS += -D_DISABLE_TIDENTS -D__USE_W32API -D_WIN32_IE=0x0600 \ + -D_WIN32_WINNT=0x0501 + +TARGET_NAME = comctl32_test + +TARGET_SDKLIBS = gdi32.a comctl32.a ntdll.a + +TARGET_OBJECTS = \ + testlist.o \ + dpa.o \ + imagelist.o \ + subclass.o \ + tab.o + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk + +# EOF \ No newline at end of file diff --git a/reactos/lib/comctl32/tests/dpa.c b/reactos/lib/comctl32/tests/dpa.c new file mode 100644 index 00000000000..66da9235b35 --- /dev/null +++ b/reactos/lib/comctl32/tests/dpa.c @@ -0,0 +1,81 @@ +/* + * Unit tests for DPA functions + * + * Copyright 2003 Uwe Bonnes + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" + +#include "wine/test.h" + +static HDPA (WINAPI *pDPA_Create)(int); +static BOOL (WINAPI *pDPA_Grow)(const HDPA hdpa, INT nGrow); +static BOOL (WINAPI *pDPA_Destroy)(const HDPA hdpa); +static BOOL (WINAPI *pDPA_SetPtr)(const HDPA hdpa, INT i, LPVOID p); + +static INT CALLBACK dpa_strcmp(LPVOID pvstr1, LPVOID pvstr2, LPARAM flags) +{ + LPCSTR str1 = (LPCSTR)pvstr1; + LPCSTR str2 = (LPCSTR)pvstr2; + + return lstrcmpA (str1, str2); +} + +void DPA_test() +{ + HDPA dpa_ret; + INT int_ret; + CHAR test_str0[]="test0"; + + if (!pDPA_Create) + return; + + dpa_ret = pDPA_Create(0); + ok((dpa_ret !=0), "DPA_Create failed\n"); + int_ret = DPA_Search(dpa_ret,test_str0,0, dpa_strcmp,0, DPAS_SORTED); + ok((int_ret == -1), "DPA_Search found invalid item\n"); + int_ret = DPA_Search(dpa_ret,test_str0,0, dpa_strcmp,0, DPAS_SORTED|DPAS_INSERTBEFORE); + ok((int_ret == 0), "DPA_Search proposed bad item\n"); + int_ret = DPA_Search(dpa_ret,test_str0,0, dpa_strcmp,0, DPAS_SORTED|DPAS_INSERTAFTER); + ok((int_ret == 0), "DPA_Search proposed bad item\n"); + int_ret = pDPA_Grow(dpa_ret,0); + ok(int_ret != 0, "DPA_Grow failed\n"); + int_ret = pDPA_SetPtr(dpa_ret, 0, (void*)0xdeadbeef); + ok(int_ret != 0, "DPA_SetPtr failed\n"); + int_ret = pDPA_Destroy(dpa_ret); + ok(int_ret != 0, "DPA_Destory failed\n"); +} + +START_TEST(dpa) +{ + HMODULE hdll; + + hdll=GetModuleHandleA("comctl32.dll"); + pDPA_Create=(void*)GetProcAddress(hdll,(LPCSTR)328); + pDPA_Destroy=(void*)GetProcAddress(hdll,(LPCSTR)329); + pDPA_Grow=(void*)GetProcAddress(hdll,(LPCSTR)330); + pDPA_SetPtr=(void*)GetProcAddress(hdll,(LPCSTR)335); + + DPA_test(); +} diff --git a/reactos/lib/comctl32/tests/imagelist.c b/reactos/lib/comctl32/tests/imagelist.c new file mode 100644 index 00000000000..c23eee8b93c --- /dev/null +++ b/reactos/lib/comctl32/tests/imagelist.c @@ -0,0 +1,560 @@ +/* Unit test suite for imagelist control. + * + * Copyright 2004 Michael Stefaniuc + * Copyright 2002 Mike McCormack for CodeWeavers + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "wine/test.h" + +#undef VISIBLE + +#ifdef VISIBLE +#define WAIT Sleep (1000) +#define REDRAW(hwnd) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW) +#else +#define WAIT +#define REDRAW(hwnd) +#endif + + +static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*) = NULL; + +static HDC desktopDC; +static HINSTANCE hinst; + +/* 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) +#define ROW32(a,b,c,d,e,f,g,h) ROW1(a,b,c,d,e,f,g,h), ROW1(a,b,c,d,e,f,g,h), \ + ROW1(a,b,c,d,e,f,g,h), ROW1(a,b,c,d,e,f,g,h) +#define ROW2(a,b,c,d,e,f,g,h,i,j,k,l) ROW1(a,b,c,d,e,f,g,h),B(i,j),B(k,l) +#define ROW48(a,b,c,d,e,f,g,h,i,j,k,l) ROW2(a,b,c,d,e,f,g,h,i,j,k,l), \ + ROW2(a,b,c,d,e,f,g,h,i,j,k,l), ROW2(a,b,c,d,e,f,g,h,i,j,k,l), \ + ROW2(a,b,c,d,e,f,g,h,i,j,k,l) + +static const BYTE empty_bits[48*48/8]; + +static const BYTE icon_bits[32*32/8] = +{ + ROW32(0,0,0,0,0,0,0,0), + ROW32(0,0,1,1,1,1,0,0), + ROW32(0,1,1,1,1,1,1,0), + ROW32(0,1,1,0,0,1,1,0), + ROW32(0,1,1,0,0,1,1,0), + ROW32(0,1,1,1,1,1,1,0), + ROW32(0,0,1,1,1,1,0,0), + ROW32(0,0,0,0,0,0,0,0) +}; + +static const BYTE bitmap_bits[48*48/8] = +{ + ROW48(0,0,0,0,0,0,0,0,0,0,0,0), + ROW48(0,1,1,1,1,1,1,1,1,1,1,0), + ROW48(0,1,1,0,0,0,0,0,0,1,1,0), + ROW48(0,1,0,0,0,0,0,0,1,0,1,0), + ROW48(0,1,0,0,0,0,0,1,0,0,1,0), + ROW48(0,1,0,0,0,0,1,0,0,0,1,0), + ROW48(0,1,0,0,0,1,0,0,0,0,1,0), + ROW48(0,1,0,0,1,0,0,0,0,0,1,0), + ROW48(0,1,0,1,0,0,0,0,0,0,1,0), + ROW48(0,1,1,0,0,0,0,0,0,1,1,0), + ROW48(0,1,1,1,1,1,1,1,1,1,1,0), + ROW48(0,0,0,0,0,0,0,0,0,0,0,0) +}; + +static HIMAGELIST createImageList(cx, cy) +{ + /* Create an ImageList and put an image into it */ + HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR, 1, 1); + HBITMAP hbm = CreateBitmap(48, 48, 1, 1, bitmap_bits); + ImageList_Add(himl, hbm, NULL); + return himl; +} + +static HWND create_a_window(void) +{ + char className[] = "bmwnd"; + char winName[] = "Test Bitmap"; + HWND hWnd; + static int registered = 0; + + if (!registered) + { + WNDCLASSA cls; + + cls.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS; + cls.lpfnWndProc = DefWindowProcA; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = 0; + cls.hIcon = LoadIconA (0, (LPSTR)IDI_APPLICATION); + cls.hCursor = LoadCursorA (0, (LPSTR)IDC_ARROW); + cls.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); + cls.lpszMenuName = 0; + cls.lpszClassName = className; + + RegisterClassA (&cls); + registered = 1; + } + + /* Setup window */ + hWnd = CreateWindowA (className, winName, + WS_OVERLAPPEDWINDOW , + CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, + 0, hinst, 0); + +#ifdef VISIBLE + ShowWindow (hWnd, SW_SHOW); +#endif + REDRAW(hWnd); + WAIT; + + return hWnd; +} + +static HDC show_image(HWND hwnd, HIMAGELIST himl, int idx, int size, + LPCSTR loc, BOOL clear) +{ + HDC hdc = NULL; +#ifdef VISIBLE + if (!himl) return NULL; + + SetWindowText(hwnd, loc); + hdc = GetDC(hwnd); + ImageList_Draw(himl, idx, hdc, 0, 0, ILD_TRANSPARENT); + + REDRAW(hwnd); + WAIT; + + if (clear) + { + BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY); + ReleaseDC(hwnd, hdc); + hdc = NULL; + } +#endif /* VISIBLE */ + return hdc; +} + +/* Useful for checking differences */ +#if 0 +static void dump_bits(const BYTE *p, const BYTE *q, int size) +{ + int i, j; + + size /= 8; + + for (i = 0; i < size * 2; i++) + { + printf("|"); + for (j = 0; j < size; j++) + printf("%c%c", p[j] & 0xf0 ? 'X' : ' ', p[j] & 0xf ? 'X' : ' '); + printf(" -- "); + for (j = 0; j < size; j++) + printf("%c%c", q[j] & 0xf0 ? 'X' : ' ', q[j] & 0xf ? 'X' : ' '); + printf("|\n"); + p += size * 4; + q += size * 4; + } + printf("\n"); +} +#endif + +static void check_bits(HWND hwnd, HIMAGELIST himl, int idx, int size, + const BYTE *checkbits, LPCSTR loc) +{ +#ifdef VISIBLE + BYTE bits[100*100/8]; + COLORREF c; + HDC hdc; + int x, y, i = -1; + + if (!himl) return; + + memset(bits, 0, sizeof(bits)); + hdc = show_image(hwnd, himl, idx, size, loc, FALSE); + + c = GetPixel(hdc, 0, 0); + + for (y = 0; y < size; y ++) + { + for (x = 0; x < size; x++) + { + if (!(x & 0x7)) i++; + if (GetPixel(hdc, x, y) != c) bits[i] |= (0x80 >> (x & 0x7)); + } + } + + BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY); + ReleaseDC(hwnd, hdc); + + ok (memcmp(bits, checkbits, (size * size)/8) == 0, + "%s: bits different\n", loc); + if (memcmp(bits, checkbits, (size * size)/8)) + dump_bits(bits, checkbits, size); +#endif /* VISIBLE */ +} + +static void testHotspot (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, ret; + HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1); + HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2); + HWND hwnd = create_a_window(); + + + 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]; + HIMAGELIST himlNew; + POINT ppt; + + ret = ImageList_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); + 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); + ok(ppt.x == dx1 && ppt.y == dy1, + "Expected drag hotspot [%d,%d] got [%ld,%ld]\n", + dx1, dy1, ppt.x, ppt.y); + /* check size of new dragged image */ + ImageList_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, + "Expected drag image size [%d,%d] got [%d,%d]\n", + correctx, correcty, newx, newy); + sprintf(loc, "GetDragImage (%d,%d)\n", i, j); + show_image(hwnd, himlNew, 0, max(correctx, correcty), loc, TRUE); + ImageList_EndDrag(); + } + } +#undef SIZEX1 +#undef SIZEY1 +#undef SIZEX2 +#undef SIZEY2 +#undef HOTSPOTS_MAX + DestroyWindow(hwnd); +} + +static BOOL DoTest1(void) +{ + HIMAGELIST himl ; + + HICON hicon1 ; + HICON hicon2 ; + HICON hicon3 ; + + /* create an imagelist to play with */ + himl = ImageList_Create(84,84,0x10,0,3); + ok(himl!=0,"failed to create imagelist\n"); + + /* load the icons to add to the image list */ + hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits); + ok(hicon1 != 0, "no hicon1\n"); + hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits); + ok(hicon2 != 0, "no hicon2\n"); + hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits); + ok(hicon3 != 0, "no hicon3\n"); + + /* remove when nothing exists */ + ok(!ImageList_Remove(himl,0),"removed non-existent icon\n"); + /* removing everything from an empty imagelist should succeed */ + ok(ImageList_RemoveAll(himl),"removed non-existent 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"); + + /* remove an index out of range */ + ok(!ImageList_Remove(himl,4711),"removed non-existent 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"); + + /* remove one extra */ + ok(!ImageList_Remove(himl,0),"removed non-existent icon\n"); + + /* destroy it */ + ok(ImageList_Destroy(himl),"destroy imagelist failed\n"); + + /* icons should be deleted by the imagelist */ + ok(!DeleteObject(hicon1),"icon 1 wasn't deleted\n"); + ok(!DeleteObject(hicon2),"icon 2 wasn't deleted\n"); + ok(!DeleteObject(hicon3),"icon 3 wasn't deleted\n"); + + return TRUE; +} + +static BOOL DoTest2(void) +{ + HIMAGELIST himl ; + + HICON hicon1 ; + HICON hicon2 ; + HICON hicon3 ; + + /* create an imagelist to play with */ + himl = ImageList_Create(84,84,0x10,0,3); + ok(himl!=0,"failed to create imagelist\n"); + + /* load the icons to add to the image list */ + hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits); + ok(hicon1 != 0, "no hicon1\n"); + hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits); + ok(hicon2 != 0, "no hicon2\n"); + hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits); + ok(hicon3 != 0, "no hicon3\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"); + + /* destroy it */ + ok(ImageList_Destroy(himl),"destroy imagelist failed\n"); + + /* icons should be deleted by the imagelist */ + ok(!DeleteObject(hicon1),"icon 1 wasn't deleted\n"); + ok(!DeleteObject(hicon2),"icon 2 wasn't deleted\n"); + ok(!DeleteObject(hicon3),"icon 3 wasn't deleted\n"); + + return TRUE; +} + +static BOOL DoTest3(void) +{ + HIMAGELIST himl; + + HBITMAP hbm1; + HBITMAP hbm2; + HBITMAP hbm3; + + IMAGELISTDRAWPARAMS imldp; + HDC hdc; + HWND hwndfortest; + + if (!pImageList_DrawIndirect) + { + HMODULE hComCtl32 = LoadLibraryA("comctl32.dll"); + pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect"); + if (!pImageList_DrawIndirect) + { + trace("ImageList_DrawIndirect not available, skipping test\n"); + return TRUE; + } + } + + hwndfortest = create_a_window(); + hdc = GetDC(hwndfortest); + ok(hdc!=NULL, "couldn't get DC\n"); + + /* create an imagelist to play with */ + himl = ImageList_Create(48,48,0x10,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(hbm1 != 0, "no bitmap 1\n"); + hbm2 = CreateBitmap(48, 48, 1, 1, bitmap_bits); + ok(hbm2 != 0, "no bitmap 2\n"); + hbm3 = 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(ImageList_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"); + + memset(&imldp, 0, sizeof (imldp)); + ok(!pImageList_DrawIndirect(&imldp), "zero data succeeded!\n"); + imldp.cbSize = sizeof (imldp); + ok(!pImageList_DrawIndirect(&imldp), "zero hdc succeeded!\n"); + imldp.hdcDst = hdc; + ok(!pImageList_DrawIndirect(&imldp),"zero himl succeeded!\n"); + imldp.himl = himl; + if (!pImageList_DrawIndirect(&imldp)) + { + /* Earlier versions of native comctl32 use a smaller structure */ + imldp.cbSize -= 3 * sizeof(DWORD); + ok(pImageList_DrawIndirect(&imldp),"DrawIndirect should succeed\n"); + } + REDRAW(hwndfortest); + WAIT; + + imldp.fStyle = SRCCOPY; + imldp.rgbBk = CLR_DEFAULT; + imldp.rgbFg = CLR_DEFAULT; + imldp.y = 100; + imldp.x = 100; + ok(pImageList_DrawIndirect(&imldp),"should succeed\n"); + imldp.i ++; + ok(pImageList_DrawIndirect(&imldp),"should succeed\n"); + imldp.i ++; + ok(pImageList_DrawIndirect(&imldp),"should succeed\n"); + imldp.i ++; + 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"); + + /* destroy it */ + ok(ImageList_Destroy(himl),"destroy imagelist failed\n"); + + /* bitmaps should not be deleted by the imagelist */ + ok(DeleteObject(hbm1),"bitmap 1 can't be deleted\n"); + ok(DeleteObject(hbm2),"bitmap 2 can't be deleted\n"); + ok(DeleteObject(hbm3),"bitmap 3 can't be deleted\n"); + + ReleaseDC(hwndfortest, hdc); + DestroyWindow(hwndfortest); + + return TRUE; +} + +static void testMerge() +{ + HIMAGELIST himl1, himl2, hmerge; + HICON hicon1; + HWND hwnd = create_a_window(); + + himl1 = ImageList_Create(32,32,0,0,3); + ok(himl1 != NULL,"failed to create himl1\n"); + + himl2 = ImageList_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); + ok(hicon1 != NULL, "failed to create hicon1\n"); + + if (!himl1 || !himl2 || !hicon1) + return; + + ok(0==ImageList_AddIcon(himl2, hicon1),"add icon1 to himl2 failed\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); + ok(hmerge != NULL, "merge himl1,-1 failed\n"); + check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,-1"); + if (hmerge) ImageList_Destroy(hmerge); + + hmerge = ImageList_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); + + /* Same happens if himl2 is empty */ + ImageList_Destroy(himl2); + himl2 = ImageList_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); + ok(hmerge != NULL, "merge himl2,-1 failed\n"); + check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,-1"); + if (hmerge) ImageList_Destroy(hmerge); + + hmerge = ImageList_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); + + /* Now try merging an image with itself */ + ok(0==ImageList_AddIcon(himl2, hicon1),"re-add icon1 to himl2 failed\n"); + + hmerge = ImageList_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); + + /* Try merging 2 different image lists */ + ok(0==ImageList_AddIcon(himl1, hicon1),"add icon1 to himl1 failed\n"); + + hmerge = ImageList_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); + + hmerge = ImageList_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); + + ImageList_Destroy(himl1); + ImageList_Destroy(himl2); + DeleteObject(hicon1); + DestroyWindow(hwnd); +} + +START_TEST(imagelist) +{ + desktopDC=GetDC(NULL); + hinst = GetModuleHandleA(NULL); + + InitCommonControls(); + + testHotspot(); + DoTest1(); + DoTest2(); + DoTest3(); + testMerge(); +} diff --git a/reactos/lib/comctl32/tests/subclass.c b/reactos/lib/comctl32/tests/subclass.c new file mode 100644 index 00000000000..268eed912ca --- /dev/null +++ b/reactos/lib/comctl32/tests/subclass.c @@ -0,0 +1,298 @@ +/* Unit tests for subclassed windows. + * + * Copyright 2004 Kevin Koltzau + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#define _WIN32_WINNT 0x0501 /* For SetWindowSubclass/etc */ + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "commctrl.h" + +#include "wine/test.h" + +static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); +static BOOL (WINAPI *pRemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR); +static LRESULT (WINAPI *pDefSubclassProc)(HWND, UINT, WPARAM, LPARAM); + +#define SEND_NEST 0x01 +#define DELETE_SELF 0x02 +#define DELETE_PREV 0x04 + +struct message { + int procnum; /* WndProc id message is expected from */ + WPARAM wParam; /* expected value of wParam */ +}; + +static int sequence_cnt, sequence_size; +static struct message* sequence; + +static const struct message Sub_BasicTest[] = { + { 2, 1 }, + { 1, 1 }, + { 2, 2 }, + { 1, 2 }, + { 0 } +}; + +static const struct message Sub_DeletedTest[] = { + { 2, 1 }, + { 1, 1 }, + { 0 } +}; + +static const struct message Sub_AfterDeletedTest[] = { + { 1, 1 }, + { 0 } +}; + +static const struct message Sub_OldAfterNewTest[] = { + { 3, 1 }, + { 2, 1 }, + { 1, 1 }, + { 3, 2 }, + { 2, 2 }, + { 1, 2 }, + { 0 } +}; + +static const struct message Sub_MixTest[] = { + { 3, 1 }, + { 4, 1 }, + { 2, 1 }, + { 1, 1 }, + { 0 } +}; + +static const struct message Sub_MixAndNestTest[] = { + { 3, 1 }, + { 4, 1 }, + { 3, 2 }, + { 4, 2 }, + { 2, 2 }, + { 1, 2 }, + { 2, 1 }, + { 1, 1 }, + { 0 } +}; + +static const struct message Sub_MixNestDelTest[] = { + { 3, 1 }, + { 4, 1 }, + { 3, 2 }, + { 2, 2 }, + { 1, 2 }, + { 2, 1 }, + { 1, 1 }, + { 0 } +}; + +static const struct message Sub_MixDelPrevTest[] = { + { 3, 1 }, + { 5, 1 }, + { 2, 1 }, + { 1, 1 }, + { 0 } +}; + +static void add_message(const struct message *msg) +{ + if (!sequence) + { + sequence_size = 10; + sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) ); + } + if (sequence_cnt == sequence_size) + { + sequence_size *= 2; + sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) ); + } + assert(sequence); + + sequence[sequence_cnt].wParam = msg->wParam; + sequence[sequence_cnt].procnum = msg->procnum; + + sequence_cnt++; +} + +static void flush_sequence() +{ + HeapFree(GetProcessHeap(), 0, sequence); + sequence = 0; + sequence_cnt = sequence_size = 0; +} + +static void ok_sequence(const struct message *expected, const char *context) +{ + static const struct message end_of_sequence = { 0, 0 }; + const struct message *actual; + + add_message(&end_of_sequence); + + actual = sequence; + + while(expected->procnum && actual->procnum) + { + ok(expected->procnum == actual->procnum, + "%s: the procnum %d was expected, but got procnum %d instead\n", + context, expected->procnum, actual->procnum); + ok(expected->wParam == actual->wParam, + "%s: in procnum %d expecting wParam 0x%x got 0x%x\n", + context, expected->procnum, expected->wParam, actual->wParam); + expected++; + actual++; + } + ok(!expected->procnum, "Received fewer messages than expected\n"); + ok(!actual->procnum, "Received more messages than expected\n"); + flush_sequence(); +} + +static LRESULT WINAPI WndProc1(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + struct message msg; + + if(message == WM_USER) { + msg.wParam = wParam; + msg.procnum = 1; + add_message(&msg); + } + return DefWindowProc(hwnd, message, wParam, lParam); +} + + +static WNDPROC origProc3; +static LRESULT WINAPI WndProc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + struct message msg; + + if(message == WM_USER) { + msg.wParam = wParam; + msg.procnum = 3; + add_message(&msg); + } + return CallWindowProc(origProc3, hwnd, message, wParam, lParam); +} + +static LRESULT WINAPI WndProcSub(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uldSubclass, DWORD_PTR dwRefData) +{ + struct message msg; + + if(message == WM_USER) { + msg.wParam = wParam; + msg.procnum = uldSubclass; + add_message(&msg); + + if(lParam) { + if(dwRefData & DELETE_SELF) { + pRemoveWindowSubclass(hwnd, WndProcSub, uldSubclass); + pRemoveWindowSubclass(hwnd, WndProcSub, uldSubclass); + } + if(dwRefData & DELETE_PREV) + pRemoveWindowSubclass(hwnd, WndProcSub, uldSubclass-1); + if(dwRefData & SEND_NEST) + SendMessage(hwnd, WM_USER, wParam+1, 0); + } + } + return pDefSubclassProc(hwnd, message, wParam, lParam); +} + +static void test_subclass() +{ + HWND hwnd = CreateWindowExA(0, "TestSubclass", "Test subclass", WS_OVERLAPPEDWINDOW, + 100, 100, 200, 200, 0, 0, 0, NULL); + assert(hwnd); + + pSetWindowSubclass(hwnd, WndProcSub, 2, 0); + SendMessage(hwnd, WM_USER, 1, 0); + SendMessage(hwnd, WM_USER, 2, 0); + ok_sequence(Sub_BasicTest, "Basic"); + + pSetWindowSubclass(hwnd, WndProcSub, 2, DELETE_SELF); + SendMessage(hwnd, WM_USER, 1, 1); + ok_sequence(Sub_DeletedTest, "Deleted"); + + SendMessage(hwnd, WM_USER, 1, 0); + ok_sequence(Sub_AfterDeletedTest, "After Deleted"); + + pSetWindowSubclass(hwnd, WndProcSub, 2, 0); + origProc3 = (WNDPROC)SetWindowLong(hwnd, GWL_WNDPROC, (LONG)WndProc3); + SendMessage(hwnd, WM_USER, 1, 0); + SendMessage(hwnd, WM_USER, 2, 0); + ok_sequence(Sub_OldAfterNewTest, "Old after New"); + + pSetWindowSubclass(hwnd, WndProcSub, 4, 0); + SendMessage(hwnd, WM_USER, 1, 0); + ok_sequence(Sub_MixTest, "Mix"); + + /* Now the fun starts */ + pSetWindowSubclass(hwnd, WndProcSub, 4, SEND_NEST); + SendMessage(hwnd, WM_USER, 1, 1); + ok_sequence(Sub_MixAndNestTest, "Mix and nest"); + + pSetWindowSubclass(hwnd, WndProcSub, 4, SEND_NEST | DELETE_SELF); + SendMessage(hwnd, WM_USER, 1, 1); + ok_sequence(Sub_MixNestDelTest, "Mix, nest, del"); + + pSetWindowSubclass(hwnd, WndProcSub, 4, 0); + pSetWindowSubclass(hwnd, WndProcSub, 5, DELETE_PREV); + SendMessage(hwnd, WM_USER, 1, 1); + ok_sequence(Sub_MixDelPrevTest, "Mix and del prev"); + + DestroyWindow(hwnd); +} + +static BOOL RegisterWindowClasses(void) +{ + WNDCLASSA cls; + + cls.style = 0; + cls.lpfnWndProc = WndProc1; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(0); + cls.hIcon = 0; + cls.hCursor = NULL; + cls.hbrBackground = NULL; + cls.lpszMenuName = NULL; + cls.lpszClassName = "TestSubclass"; + if(!RegisterClassA(&cls)) return FALSE; + + return TRUE; +} + +START_TEST(subclass) +{ + HMODULE hdll; + + hdll = GetModuleHandleA("comctl32.dll"); + assert(hdll); + pSetWindowSubclass = (void*)GetProcAddress(hdll, "SetWindowSubclass"); + pRemoveWindowSubclass = (void*)GetProcAddress(hdll, "RemoveWindowSubclass"); + pDefSubclassProc = (void*)GetProcAddress(hdll, "DefSubclassProc"); + + if(!pSetWindowSubclass || !pRemoveWindowSubclass || !pDefSubclassProc) + return; + + if(!RegisterWindowClasses()) assert(0); + + test_subclass(); +} diff --git a/reactos/lib/comctl32/tests/tab.c b/reactos/lib/comctl32/tests/tab.c new file mode 100644 index 00000000000..23234d3b6d1 --- /dev/null +++ b/reactos/lib/comctl32/tests/tab.c @@ -0,0 +1,197 @@ +/* Unit test suite for tab control. + * + * Copyright 2003 Vitaliy Margolen + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include "wine/test.h" + +#undef VISIBLE + +#define TAB_DEFAULT_WIDTH 96 +#define TAB_PADDING_X 2 +#define TAB_PADDING_Y 2 + +#ifdef VISIBLE +#define WAIT Sleep (1000) +#define REDRAW(hwnd) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW) +#define trace_tab(str) trace(str) +#else +#define WAIT +#define REDRAW(hwnd) +#define trace_tab(str) +#endif + +HWND +create_tabcontrol (DWORD style) +{ + HWND handle; + TCITEM tcNewTab; + + handle = CreateWindow ( + WC_TABCONTROLA, + "TestTab", + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style, + 10, 10, 300, 100, + NULL, NULL, NULL, 0); + + assert (handle); + + SetWindowLong(handle, GWL_STYLE, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style); + + tcNewTab.mask = TCIF_TEXT | TCIF_IMAGE; + tcNewTab.pszText = "Tab 1"; + tcNewTab.iImage = 0; + SendMessage (handle, TCM_INSERTITEM, 0, (LPARAM) &tcNewTab); + tcNewTab.pszText = "Wide Tab 2"; + tcNewTab.iImage = 1; + SendMessage (handle, TCM_INSERTITEM, 1, (LPARAM) &tcNewTab); + tcNewTab.pszText = "T 3"; + tcNewTab.iImage = 2; + SendMessage (handle, TCM_INSERTITEM, 2, (LPARAM) &tcNewTab); + +#ifdef VISIBLE + ShowWindow (handle, SW_SHOW); +#endif + REDRAW(handle); + WAIT; + + return handle; +} + +void CheckSize(HWND hwnd, INT width, INT height) +{ + RECT rTab, r1; + + r1.left=r1.top=r1.right=r1.bottom=0; + SendMessage (hwnd, TCM_GETITEMRECT, 0, (LPARAM) &rTab); + SendMessage (hwnd, TCM_ADJUSTRECT, FALSE, (LPARAM) &r1); + /* trace ("Got (%ld,%ld)-(%ld,%ld)\n", rTab.left, rTab.top, rTab.right, rTab.bottom); */ + trace (" (%ld,%ld)-(%ld,%ld)\n", r1.left, r1.top, r1.right, r1.bottom); + if ((width >= 0) && (height < 0)) + ok (width == rTab.right - rTab.left, "Expected [%d] got [%ld]\n", width, rTab.right - rTab.left); + else if ((height >= 0) && (width < 0)) + ok (height == rTab.bottom - rTab.top, "Expected [%d] got [%ld]\n", height, rTab.bottom - rTab.top); + else + ok ((width == rTab.right - rTab.left) && + (height == rTab.bottom - rTab.top ), + "Expected [%d,%d] got [%ld,%ld]\n", width, height, rTab.right - rTab.left, rTab.bottom - rTab.top); +} + +void TabCheckSetSize(HWND hwnd, INT SetWidth, INT SetHeight, INT ExpWidth, INT ExpHeight) +{ + SendMessage (hwnd, TCM_SETITEMSIZE, 0, + (LPARAM) MAKELPARAM((SetWidth >= 0) ? SetWidth:0, (SetHeight >= 0) ? SetHeight:0)); + REDRAW(hwnd); + CheckSize(hwnd, ExpWidth, ExpHeight); + WAIT; +} + +START_TEST(tab) +{ + HWND hwTab; + HIMAGELIST himl = ImageList_Create(21, 21, ILC_COLOR, 3, 4); + + InitCommonControls(); + + + hwTab = create_tabcontrol(TCS_FIXEDWIDTH); + + trace_tab ("Testing TCS_FIXEDWIDTH tabs no icon...\n"); + trace_tab (" default width...\n"); + CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1); + trace_tab (" set size...\n"); + TabCheckSetSize(hwTab, 50, 20, 50, 20); + WAIT; + trace_tab (" min size...\n"); + TabCheckSetSize(hwTab, 0, 1, 0, 1); + WAIT; + + SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl); + + trace_tab ("Testing TCS_FIXEDWIDTH tabs with icon...\n"); + trace_tab (" set size > icon...\n"); + TabCheckSetSize(hwTab, 50, 30, 50, 30); + trace_tab (" set size < icon...\n"); + TabCheckSetSize(hwTab, 20, 20, 25, 20); + trace_tab (" min size...\n"); + TabCheckSetSize(hwTab, 0, 1, 25, 1); + + DestroyWindow (hwTab); + + trace_tab ("Testing TCS_FIXEDWIDTH buttons no icon...\n"); + hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BUTTONS); + + trace_tab (" default width...\n"); + CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1); + trace_tab (" set size 1...\n"); + TabCheckSetSize(hwTab, 20, 20, 20, 20); + trace_tab (" set size 2...\n"); + TabCheckSetSize(hwTab, 10, 50, 10, 50); + trace_tab (" min size...\n"); + TabCheckSetSize(hwTab, 0, 1, 0, 1); + + SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl); + + trace_tab ("Testing TCS_FIXEDWIDTH buttons with icon...\n"); + trace_tab (" set size > icon...\n"); + TabCheckSetSize(hwTab, 50, 30, 50, 30); + trace_tab (" set size < icon...\n"); + TabCheckSetSize(hwTab, 20, 20, 25, 20); + trace_tab (" min size...\n"); + TabCheckSetSize(hwTab, 0, 1, 25, 1); + trace_tab (" Add padding...\n"); + SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4,4)); + trace_tab (" min size...\n"); + TabCheckSetSize(hwTab, 0, 1, 25, 1); + + DestroyWindow (hwTab); + + hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BOTTOM); + trace_tab ("Testing TCS_FIXEDWIDTH | TCS_BOTTOM tabs no icon...\n"); + + trace_tab (" default width...\n"); + CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1); + trace_tab (" set size 1...\n"); + TabCheckSetSize(hwTab, 20, 20, 20, 20); + trace_tab (" set size 2...\n"); + TabCheckSetSize(hwTab, 10, 50, 10, 50); + trace_tab (" min size...\n"); + TabCheckSetSize(hwTab, 0, 1, 0, 1); + + SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl); + + trace_tab ("Testing TCS_FIXEDWIDTH | TCS_BOTTOM tabs with icon...\n"); + trace_tab (" set size > icon...\n"); + TabCheckSetSize(hwTab, 50, 30, 50, 30); + trace_tab (" set size < icon...\n"); + TabCheckSetSize(hwTab, 20, 20, 25, 20); + trace_tab (" min size...\n"); + TabCheckSetSize(hwTab, 0, 1, 25, 1); + trace_tab (" Add padding...\n"); + SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4,4)); + trace_tab (" min size...\n"); + TabCheckSetSize(hwTab, 0, 1, 25, 1); + + DestroyWindow (hwTab); + + + ImageList_Destroy(himl); +} diff --git a/reactos/lib/comctl32/tests/testlist.c b/reactos/lib/comctl32/tests/testlist.c new file mode 100644 index 00000000000..c8bcc6f3b4d --- /dev/null +++ b/reactos/lib/comctl32/tests/testlist.c @@ -0,0 +1,31 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +/* stdarg.h is needed for Winelib */ +#include +#include +#include +#include "windef.h" +#include "winbase.h" + +extern void func_dpa(void); +extern void func_imagelist(void); +extern void func_subclass(void); +extern void func_tab(void); + +struct test +{ + const char *name; + void (*func)(void); +}; + +static const struct test winetest_testlist[] = +{ + { "dpa", func_dpa }, + { "imagelist", func_imagelist }, + { "subclass", func_subclass }, + { "tab", func_tab }, + { 0, 0 } +}; + +#define WINETEST_WANT_MAIN +#include "wine/test.h"