Added Wine regression tests for comctl32. (Untested)
Added: trunk/reactos/lib/comctl32/winetest/
Added: trunk/reactos/lib/comctl32/winetest/dpa.c
Added: trunk/reactos/lib/comctl32/winetest/imagelist.c
Added: trunk/reactos/lib/comctl32/winetest/makefile
Added: trunk/reactos/lib/comctl32/winetest/mru.c
Added: trunk/reactos/lib/comctl32/winetest/subclass.c
Added: trunk/reactos/lib/comctl32/winetest/tab.c
Added: trunk/reactos/lib/comctl32/winetest/testlist.c

Added: trunk/reactos/lib/comctl32/winetest/dpa.c
--- trunk/reactos/lib/comctl32/winetest/dpa.c	2005-03-12 02:04:08 UTC (rev 13949)
+++ trunk/reactos/lib/comctl32/winetest/dpa.c	2005-03-12 04:09:57 UTC (rev 13950)
@@ -0,0 +1,80 @@
+/*
+ * 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 <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.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();
+}

Added: trunk/reactos/lib/comctl32/winetest/imagelist.c
--- trunk/reactos/lib/comctl32/winetest/imagelist.c	2005-03-12 02:04:08 UTC (rev 13949)
+++ trunk/reactos/lib/comctl32/winetest/imagelist.c	2005-03-12 04:09:57 UTC (rev 13950)
@@ -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 <assert.h>
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+
+#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(int cx, int 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 nonexistent icon\n");
+    /* removing everything from an empty imagelist should succeed */
+    ok(ImageList_RemoveAll(himl),"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");
+
+    /* remove an index out of range */
+    ok(!ImageList_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");
+
+    /* remove one extra */
+    ok(!ImageList_Remove(himl,0),"removed nonexistent 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();
+}

Added: trunk/reactos/lib/comctl32/winetest/makefile
--- trunk/reactos/lib/comctl32/winetest/makefile	2005-03-12 02:04:08 UTC (rev 13949)
+++ trunk/reactos/lib/comctl32/winetest/makefile	2005-03-12 04:09:57 UTC (rev 13950)
@@ -0,0 +1,31 @@
+# $Id: Makefile 12745 2005-01-03 02:37:10Z sedwards $
+
+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 -D__REACTOS__
+
+TARGET_NAME = comctl32_test
+
+TARGET_SDKLIBS = shlwapi.a gdi32.a comctl32.a ntdll.a wine.a
+
+TARGET_OBJECTS = \
+	testlist.o \
+	dpa.o \
+	imagelist.o \
+	mru.o \
+	subclass.o \
+	tab.o
+
+include $(PATH_TO_TOP)/rules.mak
+
+include $(TOOLS_PATH)/helper.mk
+
+# EOF
\ No newline at end of file

Added: trunk/reactos/lib/comctl32/winetest/mru.c
--- trunk/reactos/lib/comctl32/winetest/mru.c	2005-03-12 02:04:08 UTC (rev 13949)
+++ trunk/reactos/lib/comctl32/winetest/mru.c	2005-03-12 04:09:57 UTC (rev 13950)
@@ -0,0 +1,295 @@
+/*
+ * comctl32 MRU unit tests
+ *
+ * Copyright (C) 2004 Jon Griffiths <jon_p_griffiths@yahoo.com>
+ *
+ * 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 <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "commctrl.h"
+#include "shlwapi.h"
+
+#include "wine/test.h"
+
+/* Keys for testing MRU functions */
+#define REG_TEST_BASEKEYA    "Software\\Wine"
+#define REG_TEST_BASESUBKEYA "Test"
+#define REG_TEST_KEYA    REG_TEST_BASEKEYA "\\" REG_TEST_BASESUBKEYA
+#define REG_TEST_SUBKEYA "MRUTest"
+#define REG_TEST_FULLKEY REG_TEST_KEYA "\\" REG_TEST_SUBKEYA
+
+/* Undocumented MRU structures & functions */
+typedef struct tagCREATEMRULISTA
+{
+    DWORD   cbSize;
+    DWORD   nMaxItems;
+    DWORD   dwFlags;
+    HKEY    hKey;
+    LPCSTR  lpszSubKey;
+    PROC    lpfnCompare;
+} CREATEMRULISTA, *LPCREATEMRULISTA;
+
+#define MRUF_STRING_LIST  0
+#define MRUF_BINARY_LIST  1
+#define MRUF_DELAYED_SAVE 2
+
+#define LIST_SIZE 3 /* Max entries for each mru */
+
+static CREATEMRULISTA mruA =
+{
+    sizeof(CREATEMRULISTA),
+    LIST_SIZE,
+    0,
+    NULL,
+    REG_TEST_SUBKEYA,
+    NULL
+};
+
+static HMODULE hComctl32;
+static HANDLE (WINAPI *pCreateMRUListA)(LPCREATEMRULISTA);
+static void   (WINAPI *pFreeMRUList)(HANDLE);
+static INT    (WINAPI *pAddMRUStringA)(HANDLE,LPCSTR);
+/*
+static INT    (WINAPI *pFindMRUStringA)(HANDLE,LPCSTR,LPINT);
+static INT    (WINAPI *pEnumMRUList)(HANDLE,INT,LPVOID,DWORD);
+*/
+
+static BOOL create_reg_entries(void)
+{
+    HKEY hKey = NULL;
+
+    ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_FULLKEY, &hKey),
+       "Couldn't create test key \"%s\"\n", REG_TEST_KEYA);
+    if (!hKey) return FALSE;
+    RegCloseKey(hKey);
+    return TRUE;
+}
+
+static void delete_reg_entries(void)
+{
+    HKEY hKey;
+
+    if (RegOpenKeyExA(HKEY_CURRENT_USER, REG_TEST_BASEKEYA, 0, KEY_ALL_ACCESS,
+                      &hKey))
+        return;
+    SHDeleteKeyA(hKey, REG_TEST_BASESUBKEYA);
+    RegCloseKey(hKey);
+}
+
+static void check_reg_entries(const char *mrulist, const char**items)
+{
+    char buff[128];
+    HKEY hKey = NULL;
+    DWORD type, size, ret;
+    size_t i;
+
+    ok(!RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_FULLKEY, &hKey),
+       "Couldn't open test key \"%s\"\n", REG_TEST_FULLKEY);
+    if (!hKey) return;
+
+    type = REG_SZ;
+    size = sizeof(buff);
+    buff[0] = '\0';
+    ret = RegQueryValueExA(hKey, "MRUList", NULL, &type, (LPBYTE)buff, &size);
+
+    ok(!ret && buff[0], "Checking MRU: got %ld from RegQueryValueExW\n", ret);
+    if(ret || !buff[0]) return;
+
+    ok(strcmp(buff, mrulist) == 0, "Checking MRU: Expected list %s, got %s\n",
+       mrulist, buff);
+    if(strcmp(buff, mrulist)) return;
+
+    for (i = 0; i < strlen(mrulist); i++)
+    {
+        char name[2];
+        name[0] = mrulist[i];
+        name[1] = '\0';
+        type = REG_SZ;
+        size = sizeof(buff);
+        buff[0] = '\0';
+        ret = RegQueryValueExA(hKey, name, NULL, &type, (LPBYTE)buff, &size);
+        ok(!ret && buff[0],
+           "Checking MRU item %d ('%c'): got %ld from RegQueryValueExW\n",
+           i, mrulist[i], ret);
+        if(ret || !buff[0]) return;
+        ok(!strcmp(buff, items[mrulist[i]-'a']),
+           "Checking MRU item %d ('%c'): expected \"%s\", got \"%s\"\n",
+           i, mrulist[i], buff, items[mrulist[i] - 'a']);
+    }
+}
+
+static INT CALLBACK cmp_mru_strA(LPCVOID data1, LPCVOID data2)
+{
+    return lstrcmpiA(data1, data2);
+}
+
+static HANDLE create_mruA(HKEY hKey, DWORD flags, PROC cmp)
+{
+    mruA.dwFlags = flags;
+    mruA.lpfnCompare = cmp;
+    mruA.hKey = hKey;
+
+    SetLastError(0);
+    return pCreateMRUListA(&mruA);
+}
+
+static void test_MRUListA(void)
+{
+    const char *checks[LIST_SIZE+1];
+    HANDLE hMRU;
+    HKEY hKey;
+    INT iRet;
+
+    pCreateMRUListA = (void*)GetProcAddress(hComctl32,(LPCSTR)151);
+    pFreeMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)152);
+    pAddMRUStringA = (void*)GetProcAddress(hComctl32,(LPCSTR)153);
+    if (!pCreateMRUListA || !pFreeMRUList || !pAddMRUStringA)
+        return;
+
+#if 0 /* Create (NULL) - crashes native */
+    hMRU = pCreateMRUListA(NULL);
+#endif
+
+    /* Create (size too small) */
+    mruA.cbSize = sizeof(mruA) - 2;
+    hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
+    ok (!hMRU && !GetLastError(),
+        "CreateMRUListA(too small) expected NULL,0 got %p,%ld\n",
+        hMRU, GetLastError());
+    mruA.cbSize = sizeof(mruA);
+
+    /* Create (size too big) */
+    mruA.cbSize = sizeof(mruA) + 2;
+    hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
+    ok (!hMRU && !GetLastError(),
+        "CreateMRUListA(too big) expected NULL,0 got %p,%ld\n",
+        hMRU, GetLastError());
+    mruA.cbSize = sizeof(mruA);
+
+    /* Create (NULL hKey) */
+    hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
+    ok (!hMRU && !GetLastError(),
+        "CreateMRUListA(NULL key) expected NULL,0 got %p,%ld\n",
+        hMRU, GetLastError());
+
+    /* Create (NULL name) */
+    mruA.lpszSubKey = NULL;
+    hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
+    ok (!hMRU && !GetLastError(),
+        "CreateMRUListA(NULL name) expected NULL,0 got %p,%ld\n",
+        hMRU, GetLastError());
+    mruA.lpszSubKey = REG_TEST_SUBKEYA;
+
+    /* Create a string MRU */
+    ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_KEYA, &hKey),
+       "Couldn't create test key \"%s\"\n", REG_TEST_KEYA);
+    if (!hKey)
+        return;
+    hMRU = create_mruA(hKey, MRUF_STRING_LIST, cmp_mru_strA);
+    ok(hMRU && !GetLastError(),
+       "CreateMRUListA(string) expected non-NULL,0 got %p,%ld\n",
+       hMRU, GetLastError());
+
+    if (hMRU)
+    {
+        checks[0] = "Test 1";
+        checks[1] = "Test 2";
+        checks[2] = "Test 3";
+        checks[3] = "Test 4";
+
+        /* Add (NULL list) */
+        SetLastError(0);
+        iRet = pAddMRUStringA(NULL, checks[0]);
+        ok(iRet == -1 && !GetLastError(),
+           "AddMRUStringA(NULL list) expected -1,0 got %d,%ld\n",
+           iRet, GetLastError());
+
+        /* Add (NULL string) */
+        SetLastError(0);
+        iRet = pAddMRUStringA(hMRU, NULL);
+        ok(iRet == 0 && GetLastError() == ERROR_INVALID_PARAMETER,
+           "AddMRUStringA(NULL str) expected 0,ERROR_INVALID_PARAMETER got %d,%ld\n",
+           iRet, GetLastError());
+
+        /* Add 3 strings. Check the registry is correct after each add */
+        SetLastError(0);
+        iRet = pAddMRUStringA(hMRU, checks[0]);
+        ok(iRet == 0 && !GetLastError(),
+           "AddMRUStringA(1) expected 0,0 got %d,%ld\n",
+           iRet, GetLastError());
+        check_reg_entries("a", checks);
+
+        SetLastError(0);
+        iRet = pAddMRUStringA(hMRU, checks[1]);
+        ok(iRet == 1 && !GetLastError(),
+           "AddMRUStringA(2) expected 1,0 got %d,%ld\n",
+           iRet, GetLastError());
+        check_reg_entries("ba", checks);
+
+        SetLastError(0);
+        iRet = pAddMRUStringA(hMRU, checks[2]);
+        ok(iRet == 2 && !GetLastError(),
+           "AddMRUStringA(2) expected 2,0 got %d,%ld\n",
+           iRet, GetLastError());
+        check_reg_entries("cba", checks);
+
+        /* Add a duplicate of the 2nd string - it should move to the front,
+         * but keep the same index in the registry.
+         */
+        SetLastError(0);
+        iRet = pAddMRUStringA(hMRU, checks[1]);
+        ok(iRet == 1 && !GetLastError(),
+           "AddMRUStringA(re-add 1) expected 1,0 got %d,%ld\n",
+           iRet, GetLastError());
+        check_reg_entries("bca", checks);
+
+        /* Add a new string - replaces the oldest string + moves to the front */
+        SetLastError(0);
+        iRet = pAddMRUStringA(hMRU, checks[3]);
+        ok(iRet == 0 && !GetLastError(),
+           "AddMRUStringA(add new) expected 0,0 got %d,%ld\n",
+           iRet, GetLastError());
+        checks[0] = checks[3];
+        check_reg_entries("abc", checks);
+
+        /* Finished with this MRU */
+        pFreeMRUList(hMRU);
+    }
+
+    /* Free (NULL list) - Doesn't crash */
+    pFreeMRUList(NULL);
+}
+
+START_TEST(mru)
+{
+    hComctl32 = GetModuleHandleA("comctl32.dll");
+    if (!hComctl32)
+        return;
+
+    delete_reg_entries();
+    if (!create_reg_entries())
+        return;
+
+    test_MRUListA();
+
+    delete_reg_entries();
+}

Added: trunk/reactos/lib/comctl32/winetest/subclass.c
--- trunk/reactos/lib/comctl32/winetest/subclass.c	2005-03-12 02:04:08 UTC (rev 13949)
+++ trunk/reactos/lib/comctl32/winetest/subclass.c	2005-03-12 04:09:57 UTC (rev 13950)
@@ -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.
[truncated at 1000 lines; 530 more skipped]