Release 980614

Sun Jun 15 10:30:35 1998  Andreas Mohr <100.30936@germany.net>

	* [files/dos_fs.c] [files/file.c] [if1632/wprocs.spec]
	  [misc/aspi.c]
	Added support for scanners that need Adaptec's ASPI2DOS.

	* [graphics/env.c] [misc/printerdrv.c] [graphics/win16drv/init.c]
	  [if1632/gdi.spec] [include/gdi.h]
	Enhanced printer support (especially Win95):
	Drv[GS]etPrinterData, [GS]etEnvironment; added AbortProc handling.

	* [misc/tapi32.c] [relay32/tapi32.spec]
	Added some stubs.

	* [configure.in] [graphics/fontengine.c] [include/windows.h]
	  [misc/comm.c] [misc/w32skrnl.c] [misc/win32s16.c]
	Made Wine compile on HP-UX (just for fun ;)

	* [controls/menu.c] [include/windows.h]
	Complete rewrite of EnableMenuItem32.
	Free Agent 32 still doesn't work :(

	* [misc/version.c] [if1632/kernel.spec] [include/winbase.h]
	Implemented GetVersionEx16.

	* [misc/network.c] [if1632/user.spec]
	Fixed arguments of WNetGetPropertyText.

	* [misc/version.c] [relay32/comctl32.spec] [relay32/oleaut32.spec]
	Implemented COMCTL32_DllGetVersion, OaBuildVersion.

	* [win32/file.c]
	Fixed UNC handling of CreateFile32.

Sat Jun 13 22:35:12 1998  Douglas Ridgway  <ridgway@winehq.com>

	* [Makefile.in] [Make.rules.in]
	Added pattern for CVS merge files to 'make clean'

	* [ole/olecli.c] [windows/scroll.c] [windows/grahics.c]
	Add some DC handle unlocking. (When hdc's are always unlocked,
	they can be made moveable.)

	* [documentation/wine.texinfo] 
	Started a Wine Design chapter with discussion of 
	graphics driver model.

Sat Jun 13 11:19:25 1998  David Luyer <luyer@ucs.uwa.edu.au>

	* [misc/main.c] [relay32/relay386.c]
	Added new option -debugmsg +relay=.... or -debugmsg -relay=...

Fri Jun 12 22:56:09 1998  Marcus Meissner <marcus@jet.franken.de>

	* [relay32/snoop.c][relay32/builtin.c][loader/pe_image.c]
	Added inter win32 dll snooping. Use -debugmsg +snoop.
	Number of arguments and string references are autodetected.
	Some small bugfixes in the PE loader.

	* [misc/system.c]
	Disabled SystemTimers. They do not work with the current
	%fs handling in the 32->16 relaycode. (helps labview)

	* [msdos/dpmi.c][msdos/int2f.c][files/drive.c]
	Added a monoton linear increasing memory allocator for DPMI (required
	for LabView, HAFAS, ...)
	mscdex handling in emulated realmode interrupts (for mcicda.drv)
	allocate logical drives only once. (helps Myst)

	* [files/profile.c]
	Handle ^Z as space. Found on CDROMS (helps Myst Installer).

	* [multimedia/mmio.c]
	mmio* partially updated to win32. No funny additions.

	* [windows/driver.c]
	Added win32 driver handling (will be used for win32 multimedia/
	msvideo drivers).

	* [win32/device.c]
	Added device handling (K32OBJ_DEVICE_IOCTL). Implemented 
	VTDAPI.5 (used by win95' WINMM.timeGetTime())

Fri Jun 12 18:01:18 1998 Rein Klazes <rklazes@casema.net>

	* [ole/compobj.c relay32/ole32.spec]
	Add a stub for CoLockObjectExternal32.

	* [objects/clipping.c]
	Fix in IntersectClipRect(), when there is no initial clipping
	region.

	* [graphics/x11drv/graphics.c]
	Corrected several "one-off" errors for the Ellipse, Rectangle
	and RoundRectangle (especially small ones) draw routines. 
	Arc and friends still have to be done.

Fri Jun 12 06:23:19 1998  Matthew Becker <mbecker@glasscity.net>

	* [misc/ntdll.c]
	Fixed some of the parameter counts.

	* [misc/registry.c]
	General cleanup, documentation.
	Standard keys are allowed to be 'closed' and succeed.

	* [misc/shell.c]
	Check for correct return values from Reg* functions.

	* [win32/newfns.c]
	Added stubs for OpenDesktopA, SetThreadDesktop, and
	SetUserObjectInformationA.

Wed Jun 10  20:28:08 1998  James Juran  <jrj120@psu.edu>

	* [debugger/break.c]
	Fixed bug introduced in 980503 that broke the -debug command 
	line option for PE executable files.

	* [configure.in] [include/acconfig.h] [include/debugtools.h]
	  [documentation/debug-msgs]
	Added 'configure' options to compile out debugging messages.
	Use --disable-debug to disable all debugging messages, and
	--disable-trace to just disable TRACE messages.  This results
	in a stripped executable that is 15-20% smaller.  This option
	is very much untested--don't expect it to work.

	* [documentation/debug-msgs] [documentation/debugging]
	Minor updates.

	* [*/*.c]
	Fixed some compile warnings.  This also includes the
	compile_warnings_trivial patch from WineHQ.

Tue Jun 10 22:00:18 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>

	* [windows/sysmetrics.c][include/sysmetrics.h]
	Fixed some Win95 values.

	* [windows/nonclient.c][include/windows.h]
	Fixed some Win95 drawing bugs.
	Added extended window style flags (WS_EX_xxx).

	* [misc/printdrv.c][relay32/winspool.spec]
	Added stubs for DeletePrinterDriver32A, DeleteMonitor32A
	and DeletePort32A.

	* [windows/mdi.c][include/windows.h][relay32/user32.spec]
	Added stubs for CascadeWindows and TileWindows.

	* [controls/toolbar.c][include/toolbar.h]
	Fixed a few bugs and implemented new features.

	* [misc/shellord.c][relay32/shell32.spec]
	Added stubs for SHELL32_60, SHELL32_61 and SHELL32_184.

	* [controls/comctl32undoc.c][relay32/comctl32.spec]
	New file comctl32undoc.c. Contains undocumented functions
	of COMCTL32.DLL. These functions are needed to run EXPLORER.EXE
	IEXPLORE.EXE and TASKMAN.EXE.

	* [controls/status.c]
	Added text alignment.

Tue Jun  8 22:00:00 1998  Bertho Stultiens <bertho@akhphd.au.dk>

	* [programs/*/Makefile.in]
	Changed the rules to use wrc as resource compiler but
	passing the source through gcc first for macro expansion.

	* [programs/*/*.rc]
	Added #include "windows.h" for the resource compiler in the
	appropriate files.

	* [tools/wrc/wrc.[ch]] [tools/wrc/writeres.c]
	Added commandline option -A for autoregister code.
	Corrected the underscore problem by checking the proper define
	from config.h.

Sun Jun  7 22:09:29 1998  Pascal Cuoq <pcuoq@ens-lyon.fr>

	* [ole/ole2nls.c] [memory/string.c]
	Improved LCMapString32A, and changed CompareString32A,
	lstrcmp, lstrcmpi to use it.

Sat Jun  6 19:00:50 1998  Martin Strömberg <ams@ludd.luth.se>

	* [include/winnt.h]
	Added typedefs for security and tokens.

Sat Jun  6 12:26:31 1998  Morten Welinder  <terra@diku.dk>

	* [objects/text.c]
	Use debugstr_an in DrawText16.

	* [loader/resource.c]
	Use debugres_w in FindResourceEx32W.  Avoid crashing during
	debug when wm is NULL.

	* [if1632/relay.c]
	In RELAY_DebugCallTo16, send output to the right place and
	avoid side effects in macro arguments.

Wed Jun  3 20:56:03 1998  Huw D M Davies <daviesh@abacus.physics.ox.ac.uk>

	* [controls/scroll.c] [windows/nonclient.c]
	Fix several off by one errors in scrollbar painting.

Tue Jun  2 23:58:59 1998  Insomnia (Stea Greene) <insomnia@core.binghamton.edu>

	* [graphics/dsound.c]
	Rewrote mixer code to handle panning and volume for 16->16, 16->8,
	8->16, and 8->8 bit mixes.  Conforms to DirectX's "logarithmic
	hearing scale" as specified in M$VC docs.  Still does not handle
	mixing of different frequencies (I am still working on that). 
	Tested 16->16 extensively with StarCraft.  Other mixing combinations
	untested but should work fine.  Still kind of a work in progress,
	so be warned.

Tue Jun  2 03:31:33 1998  Alexander V. Lukyanov <lav@long.yar.ru>

	* [tools/wrc/utils.c]
	dup_basename: fix to strip directory.

Mon Jun  1 20:00:00 1998  Juergen Schmied <juergen.schmied@metronet.de>

	* [include/windows.h] [objects/cursoricon.c] [relay32/user32.spec]
	Added stubs LoadCursorFromFileW and LoadCursorFromFileA.
diff --git a/controls/Makefile.in b/controls/Makefile.in
index ff92f5c..f36a382 100644
--- a/controls/Makefile.in
+++ b/controls/Makefile.in
@@ -8,6 +8,7 @@
 C_SRCS = \
 	button.c \
 	combo.c \
+	comctl32undoc.c \
 	commctrl.c \
 	desktop.c \
 	edit.c \
diff --git a/controls/comctl32undoc.c b/controls/comctl32undoc.c
new file mode 100644
index 0000000..2719e3b
--- /dev/null
+++ b/controls/comctl32undoc.c
@@ -0,0 +1,333 @@
+/*
+ * Undocumented functions from COMCTL32.DLL
+ *
+ * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
+ *
+ * NOTES
+ *     All of these functions are UNDOCUMENTED!! And I mean UNDOCUMENTED!!!!
+ *     Do NOT rely on names of undocumented structures and types!!!
+ *     These functions are used by EXPLORER.EXE, IEXPLORE.EXE and
+ *     COMCTL32.DLL (internally).
+ *
+ * TODO
+ *     - Fix DSA_InsertItem.
+ *     - Write documentation.
+ */
+
+#include <string.h>
+#include "windows.h"
+#include "heap.h"
+#include "debug.h"
+
+
+typedef struct _DSA_DATA
+{
+    DWORD   dwEntryCount;
+    DWORD   dwMaxCount;
+    DWORD   dwInitial;
+    DWORD   dwGrow;
+    LPSTR   *ptrs;
+} DSA_DATA, *LPDSA_DATA;
+
+
+typedef struct _DPA_DATA
+{
+    DWORD   dwEntryCount;
+    DWORD   dwMaxCount;
+    DWORD   dwGrow;
+    LPDWORD ptrs; 
+} DPA_DATA, *LPDPA_DATA;
+
+
+DWORD WINAPI Alloc (DWORD);
+DWORD WINAPI ReAlloc (DWORD, DWORD);
+DWORD WINAPI Free (DWORD);
+
+DWORD WINAPI DSA_Create (DWORD, DWORD);
+
+
+DWORD WINAPI DPA_Create (DWORD);
+DWORD WINAPI DPA_GetPtr (DWORD, DWORD);
+DWORD WINAPI DPA_InsertPtr (DWORD, DWORD, DWORD);
+
+
+LPSTR WINAPI COMCTL32_StrChrA (LPSTR lpString, CHAR cChar);
+
+
+DWORD WINAPI
+Alloc (DWORD dwParam1)
+{
+    DWORD dwPtr;
+
+    dwPtr = (DWORD)HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY, dwParam1);
+
+    TRACE (commctrl, "(0x%08lx) ret=0x%08lx\n", dwParam1, dwPtr);
+
+    return dwPtr;
+}
+
+
+DWORD WINAPI
+ReAlloc (DWORD dwParam1, DWORD dwParam2)
+{
+    DWORD dwPtr;
+
+    if (dwParam1 == 0)
+	dwPtr = (DWORD)HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY, dwParam2);
+    else
+	dwPtr = (DWORD)HeapReAlloc (SystemHeap, HEAP_ZERO_MEMORY, 
+				    (LPVOID)dwParam1, dwParam2);
+
+    TRACE (commctrl, "(0x%08lx 0x%08lx) ret=0x%08lx\n",
+	   dwParam1, dwParam2, dwPtr);
+
+    return dwPtr;
+}
+
+
+DWORD WINAPI
+Free (DWORD dwParam1)
+{
+    TRACE (commctrl, "(0x%08lx)\n", dwParam1);
+    HeapFree (SystemHeap, 0, (LPVOID)dwParam1);
+
+    return 0;
+}
+
+
+
+
+
+DWORD WINAPI
+DSA_Create (DWORD dwParam1, DWORD dwParam2)
+{
+    LPDSA_DATA dsaPtr;
+
+    dsaPtr = (LPDSA_DATA)HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY, sizeof(DSA_DATA));
+    dsaPtr->dwInitial = dwParam1;
+    dsaPtr->dwGrow = dwParam2;
+
+    TRACE (commctrl, "(0x%08lx 0x%08lx) ret=0x%08lx\n",
+	   dwParam1, dwParam2, (DWORD)dsaPtr);
+
+    return (DWORD)dsaPtr;
+}
+
+
+DWORD WINAPI
+DSA_Destroy (DWORD dwParam1)
+{
+    LPDSA_DATA dsaPtr = (LPDSA_DATA)dwParam1;
+    DWORD i;
+
+    TRACE (commctrl, "(0x%08lx):semi-stub!\n", dwParam1);
+
+    if (dsaPtr->ptrs) {
+	for (i = 0; i < dsaPtr->dwEntryCount; i++) {
+	    if (dsaPtr->ptrs[i])
+		HeapFree (SystemHeap, 0, (LPSTR)dsaPtr->ptrs[i]);
+	}
+    }
+
+    HeapFree (SystemHeap, 0, dsaPtr);
+
+    return 0;
+}
+
+
+DWORD WINAPI
+DSA_InsertItem (DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
+{
+    LPDSA_DATA dsaPtr = (LPDSA_DATA)dwParam1;
+    DWORD dwIndex;
+    INT32 len;
+
+    TRACE (commctrl, "(0x%08lx 0x%08lx \"%s\"):semi-stub!\n",
+	   dwParam1, dwParam2, (LPSTR)dwParam3);
+
+    if (dsaPtr->ptrs == NULL) {
+	dsaPtr->ptrs = (LPSTR*)HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY,
+					  dsaPtr->dwInitial * sizeof(LPVOID));
+	dsaPtr->dwMaxCount = dsaPtr->dwInitial;
+        dwIndex = 0;
+	len = lstrlen32A ((LPSTR)dwParam3);
+	dsaPtr->ptrs[dwIndex] =
+	    (LPSTR)HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY, len+1);
+	lstrcpy32A (dsaPtr->ptrs[dwIndex], (LPSTR)dwParam3);
+    }
+    else {
+	TRACE (commctrl, "(0x%08lx 0x%08lx)\n",
+	       dsaPtr->dwEntryCount, dsaPtr->dwMaxCount);
+	if (dwParam2 >= dsaPtr->dwEntryCount) {
+	    if (dsaPtr->dwEntryCount < dsaPtr->dwMaxCount) {
+		dwIndex = dsaPtr->dwEntryCount;
+		len = lstrlen32A ((LPSTR)dwParam3);
+		dsaPtr->ptrs[dwIndex] =
+		    (LPSTR)HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY, len+1);
+		lstrcpy32A (dsaPtr->ptrs[dwIndex], (LPSTR)dwParam3);
+	    }
+	    else {
+		FIXME (commctrl, "resizing array! stub!\n");
+
+		dwIndex = dwParam2;
+
+	    }
+	}
+	else {
+	    FIXME (commctrl, "inserting! stub!\n");
+
+	    dwIndex = dwParam2;
+	}
+    }
+
+    dsaPtr->dwEntryCount++;
+
+    TRACE (commctrl, "ret=0x%08lx\n", dwIndex);
+
+    return (dwIndex);
+}
+
+
+DWORD WINAPI
+DSA_GetItemPtr (DWORD dwParam1, DWORD dwParam2)
+{
+    LPDSA_DATA dsaPtr = (LPDSA_DATA)dwParam1;
+
+    TRACE (commctrl, "(0x%08lx 0x%08lx)\n", dwParam1, dwParam2);
+
+    if (dsaPtr == NULL)
+	return 0;
+    if (dsaPtr->ptrs == NULL)
+	return 0;
+    if ((dwParam2 < 0) || (dwParam2 >= dsaPtr->dwEntryCount))
+	return 0;
+
+    TRACE (commctrl, "ret=0x%08lx\n", (DWORD)dsaPtr->ptrs[dwParam2]);
+
+    return (DWORD)dsaPtr->ptrs[dwParam2];
+}
+
+
+DWORD WINAPI
+DSA_DeleteItem (DWORD dwParam1, DWORD dwParam2)
+{
+    LPDSA_DATA dsaPtr = (LPDSA_DATA)dwParam1;
+
+    TRACE (commctrl, "(0x%08lx 0x%08lx):semi-stub!\n",
+	   dwParam1, dwParam2);
+
+    if (dsaPtr->ptrs) {
+	if (dsaPtr->dwEntryCount == 1) {
+	    if (dsaPtr->ptrs[dwParam2])
+		HeapFree (SystemHeap, 0, dsaPtr->ptrs[dwParam2]);
+	    dsaPtr->dwEntryCount--;
+	}
+	else {
+	    LPSTR *oldPtrs = dsaPtr->ptrs;
+	    TRACE (commctrl, "complex delete!\n");
+
+	    if (dsaPtr->ptrs[dwParam2])
+		HeapFree (SystemHeap, 0, dsaPtr->ptrs[dwParam2]);
+
+	    dsaPtr->dwEntryCount--;
+	    dsaPtr->ptrs = 
+		(LPSTR*)HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY,
+				   dsaPtr->dwEntryCount * sizeof(LPVOID));
+	    if (dwParam2 > 0) {
+		memcpy (&dsaPtr->ptrs[0], &oldPtrs[0],
+			dwParam2 * sizeof(LPSTR));
+	    }
+
+	    if (dwParam2 < dsaPtr->dwEntryCount) {
+		memcpy (&dsaPtr->ptrs[dwParam2], &oldPtrs[dwParam2+1],
+			(dsaPtr->dwEntryCount - dwParam2) * sizeof(LPSTR));
+	    }
+	    HeapFree (SystemHeap, 0, oldPtrs);
+	}
+
+	if (dsaPtr->dwEntryCount == 0) {
+	    HeapFree (SystemHeap, 0, dsaPtr->ptrs);
+	    dsaPtr->ptrs = NULL;
+	}
+    }
+
+    return 0;
+}
+
+
+
+
+
+DWORD WINAPI
+DPA_Create (DWORD dwParam1)
+{
+    LPDPA_DATA dpaPtr;
+
+    TRACE (commctrl, "(0x%08lx)\n", dwParam1);
+
+    dpaPtr = (LPDPA_DATA)HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY, sizeof(DPA_DATA));
+    dpaPtr->dwGrow = dwParam1;
+
+    TRACE (commctrl, "ret=0x%08lx\n", (DWORD)dpaPtr);
+
+    return (DWORD)dpaPtr;
+}
+
+
+
+DWORD WINAPI
+DPA_GetPtr (DWORD dwParam1, DWORD dwParam2)
+{
+    LPDPA_DATA dpaPtr = (LPDPA_DATA)dwParam1;
+
+    TRACE (commctrl, "(0x%08lx 0x%08lx)\n", dwParam1, dwParam2);
+
+    if (dpaPtr == NULL)
+	return 0;
+    if (dpaPtr->ptrs == NULL)
+	return 0;
+    if ((dwParam2 < 0) || (dwParam2 >= dpaPtr->dwEntryCount))
+	return 0;
+
+    TRACE (commctrl, "ret=0x%08lx\n", (DWORD)dpaPtr->ptrs[dwParam2]);
+
+    return (DWORD)dpaPtr->ptrs[dwParam2];
+}
+
+
+
+DWORD WINAPI
+DPA_InsertPtr (DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
+{
+    LPDPA_DATA dpaPtr = (LPDPA_DATA)dwParam1;
+    DWORD dwIndex;
+
+    TRACE (commctrl, "(0x%08lx 0x%08lx 0x%lx)\n",
+	   dwParam1, dwParam2, dwParam3);
+
+    if (dpaPtr->ptrs == NULL) {
+	dpaPtr->ptrs = (LPDWORD)HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY,
+					   dpaPtr->dwGrow * sizeof(LPVOID));
+	dpaPtr->dwMaxCount = dpaPtr->dwGrow;
+        dwIndex = 0;
+        dpaPtr->ptrs[dwIndex] = dwParam3;
+    }
+    else {
+	FIXME (commctrl, "adding to existing array! stub!\n");
+
+
+	dwIndex = dwParam2;
+    }
+
+    dpaPtr->dwEntryCount++;
+
+    return (dwIndex);
+}
+
+
+LPSTR WINAPI
+COMCTL32_StrChrA (LPSTR lpString, CHAR cChar)
+{
+    return strchr (lpString, cChar);
+}
+
diff --git a/controls/commctrl.c b/controls/commctrl.c
index 93de092..22ef4c4 100644
--- a/controls/commctrl.c
+++ b/controls/commctrl.c
@@ -131,8 +131,8 @@
   INT32 cCount;
   DWORD dwMask;
 
-  if (lpInitCtrls == NULL) return (FALSE);
-  if (lpInitCtrls->dwSize < sizeof(INITCOMMONCONTROLSEX)) return (FALSE);
+  if (lpInitCtrls == NULL) return FALSE;
+  if (lpInitCtrls->dwSize < sizeof(INITCOMMONCONTROLSEX)) return FALSE;
 
   for (cCount = 0; cCount <= 31; cCount++) {
     dwMask = 1 << cCount;
@@ -160,6 +160,7 @@
       case ICC_TAB_CLASSES:
         TRACE (commctrl, "No tab class implemented!\n");
         TRACE (commctrl, "No tooltip class implemented!\n");
+        UPDOWN_Register ();
         break;
 
       case ICC_UPDOWN_CLASS:
@@ -178,6 +179,7 @@
         TRACE (commctrl, "No animation class implemented!\n");
         break;
 
+      /* advanced classes - not included in Win95 */
       case ICC_DATE_CLASSES:
         TRACE (commctrl, "No month calendar class implemented!\n");
         TRACE (commctrl, "No date picker class implemented!\n");
@@ -211,7 +213,7 @@
     }
   }
 
-  return (TRUE);
+  return TRUE;
 }
 
 
@@ -242,13 +244,13 @@
             }
             else {
                 if (HIWORD(wParam) & MF_POPUP) {
-                    TRACE (commctrl, "Popup menu selected!\n");
-                    FIXME (commctrl, "No popup menu texts!\n");
+                    TRACE (commctrl, "popup menu selected!\n");
+                    FIXME (commctrl, "no popup menu texts!\n");
 
                     szStatusText[0] = 0;
                 }
                 else {
-                    TRACE (commctrl, "Menu item selected!\n");
+                    TRACE (commctrl, "menu item selected!\n");
                     if (!LoadString32A (hInst, LOWORD(wParam), szStatusText, 128))
                         szStatusText[0] = 0;
                 }
@@ -284,7 +286,8 @@
     if(hwndTB) {
 	TBADDBITMAP tbab;
 
-        SendMessage32A (hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
+        SendMessage32A (hwndTB, TB_BUTTONSTRUCTSIZE,
+			(WPARAM32)uStructSize, 0);
 
 	/* set bitmap and button size */
 
@@ -296,10 +299,10 @@
 
 	/* add buttons */
 	SendMessage32A (hwndTB, TB_ADDBUTTONS32A,
-			(WPARAM32)iNumButtons, (LPARAM)&lpButtons);
+			(WPARAM32)iNumButtons, (LPARAM)lpButtons);
     }
 
-    return (hwndTB);
+    return hwndTB;
 }
 
 
@@ -341,3 +344,39 @@
 			    iNumButtons, 0, 0, 0, 0, sizeof (OLDTBBUTTON));
 }
 
+
+/***********************************************************************
+ * GetEffectiveClientRect [COMCTL32.4]
+ *
+ *
+ *
+ */
+
+VOID WINAPI
+GetEffectiveClientRect (HWND32 hwnd, LPRECT32 lpRect, LPINT32 lpInfo)
+{
+    RECT32  rcClient, rcCtrl;
+    HWND32  hwndCtrl;
+    LPINT32 lpRun;
+
+    TRACE (commctrl, "hwnd=0x%08lx lpRect=0x%08lx lpInfo=0x%08lx\n",
+	   (DWORD)hwnd, (DWORD)lpRect, (DWORD)lpInfo);
+
+    GetClientRect32 (hwnd, &rcClient);
+
+    lpRun = lpInfo;
+    TRACE (commctrl, "*lpRun=0x%08x\n", *lpRun);
+    while (*lpRun) {
+	lpRun++;
+	TRACE (commctrl, "control id 0x%08x\n", *lpRun);
+	hwndCtrl = GetDlgItem32 (hwnd, *lpRun);
+	GetWindowRect32 (hwndCtrl, &rcCtrl);
+	MapWindowPoints32 (NULL, hwnd, (LPPOINT32)&rcCtrl, 2);
+	SubtractRect32 (&rcClient, &rcClient, &rcCtrl);
+	lpRun++;
+	TRACE (commctrl, "*lpRun=0x%08x\n", *lpRun);
+    }
+
+    CopyRect32 (lpRect, &rcClient);
+}
+
diff --git a/controls/menu.c b/controls/menu.c
index 81bc680..ee407e2 100644
--- a/controls/menu.c
+++ b/controls/menu.c
@@ -2784,7 +2784,7 @@
 /**********************************************************************
  *         EnableMenuItem16    (USER.155)
  */
-BOOL16 WINAPI EnableMenuItem16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
+UINT16 WINAPI EnableMenuItem16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
 {
     return EnableMenuItem32( hMenu, wItemID, wFlags );
 }
@@ -2793,38 +2793,20 @@
 /**********************************************************************
  *         EnableMenuItem32    (USER32.170)
  */
-BOOL32 WINAPI EnableMenuItem32( HMENU32 hMenu, UINT32 wItemID, UINT32 wFlags )
+UINT32 WINAPI EnableMenuItem32( HMENU32 hMenu, UINT32 wItemID, UINT32 wFlags )
 {
-    BOOL32    bRet = FALSE;
-    MENUITEM *item, *first = NULL;
+    UINT32    oldflags;
+    MENUITEM *item;
 
     TRACE(menu,"(%04x, %04X, %04X) !\n", 
 		 hMenu, wItemID, wFlags);
 
-    while( (item = MENU_FindItem( &hMenu, &wItemID, wFlags )) )
-    {
-      if( (wFlags & MF_BYPOSITION) || !(item->fType & MF_POPUP) )
-      {
-           /* We can't have MF_GRAYED and MF_DISABLED together */
-           if (wFlags & MF_GRAYED)
-           {
-  	     item->fState = (item->fState & ~MF_DISABLED) | MF_GRAYED;
-           }
-           else if (wFlags & MF_DISABLED)
-           {
-	     item->fState = (item->fState & ~MF_GRAYED) | MF_DISABLED;
-           }
-           else   /* MF_ENABLED */
-           {
-	     item->fState &= ~(MF_GRAYED | MF_DISABLED);
-           } 
-	   bRet = TRUE;
-	   break;
-      }
-      if( !first ) first = item;
-      else if( first == item ) break;
-    }
-    return bRet;
+    if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
+	return (UINT32)-1;
+
+    oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
+    item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
+    return oldflags;
 }
 
 
diff --git a/controls/scroll.c b/controls/scroll.c
index 4f844cf..0cade01 100644
--- a/controls/scroll.c
+++ b/controls/scroll.c
@@ -46,6 +46,9 @@
   /* Minimum size of the thumb in pixels */
 #define SCROLL_MIN_THUMB 6
 
+  /* Overlap between arrows and thumb */
+#define SCROLL_ARROW_THUMB_OVERLAP 1
+
   /* Delay (in ms) before first repetition when holding the button down */
 #define SCROLL_FIRST_DELAY   200
 
@@ -159,18 +162,28 @@
     switch(nBar)
     {
       case SB_HORZ:
-        lprect->left   = wndPtr->rectClient.left - wndPtr->rectWindow.left - 1;
+        lprect->left   = wndPtr->rectClient.left - wndPtr->rectWindow.left;
         lprect->top    = wndPtr->rectClient.bottom - wndPtr->rectWindow.top;
-        lprect->right  = wndPtr->rectClient.right - wndPtr->rectWindow.left +1;
-        lprect->bottom = lprect->top + SYSMETRICS_CYHSCROLL + 1;
+        lprect->right  = wndPtr->rectClient.right - wndPtr->rectWindow.left;
+        lprect->bottom = lprect->top + SYSMETRICS_CYHSCROLL;
+	if(wndPtr->dwStyle & WS_BORDER) {
+	  lprect->left--;
+	  lprect->right++;
+	} else if(wndPtr->dwStyle & WS_VSCROLL)
+	  lprect->right++;
         vertical = FALSE;
 	break;
 
       case SB_VERT:
         lprect->left   = wndPtr->rectClient.right - wndPtr->rectWindow.left;
-        lprect->top    = wndPtr->rectClient.top - wndPtr->rectWindow.top - 1;
-        lprect->right  = lprect->left + SYSMETRICS_CXVSCROLL + 1;
-        lprect->bottom = wndPtr->rectClient.bottom - wndPtr->rectWindow.top +1;
+        lprect->top    = wndPtr->rectClient.top - wndPtr->rectWindow.top;
+        lprect->right  = lprect->left + SYSMETRICS_CXVSCROLL;
+        lprect->bottom = wndPtr->rectClient.bottom - wndPtr->rectWindow.top;
+	if(wndPtr->dwStyle & WS_BORDER) {
+	  lprect->top--;
+	  lprect->bottom++;
+	} else if(wndPtr->dwStyle & WS_HSCROLL)
+	  lprect->bottom++;
         vertical = TRUE;
 	break;
 
@@ -199,7 +212,7 @@
         SCROLLBAR_INFO *info = SCROLL_GetPtrScrollInfo( wndPtr, nBar );
 
         *arrowSize = SYSMETRICS_CXVSCROLL;
-        pixels -= 2 * SYSMETRICS_CXVSCROLL;
+        pixels -= (2 * (SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP));
 
         if (info->Page)
         {
@@ -208,7 +221,7 @@
         }
         else *thumbSize = SYSMETRICS_CXVSCROLL;
 
-        if (((pixels -= *thumbSize + 1) < 0) ||
+        if (((pixels -= *thumbSize ) < 0) ||
             ((info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH))
         {
             /* Rectangle too small or scrollbar disabled -> no thumb */
@@ -218,10 +231,10 @@
         {
             INT32 max = info->MaxVal - MAX( info->Page-1, 0 );
             if (info->MinVal >= max)
-                *thumbPos = *arrowSize;
+                *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
             else
-                *thumbPos = *arrowSize + pixels * (info->CurVal-info->MinVal) /
-                                                  (max - info->MinVal);
+                *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP
+		 + pixels * (info->CurVal-info->MinVal) / (max - info->MinVal);
         }
     }
     return vertical;
@@ -240,7 +253,8 @@
     INT32 thumbSize;
     INT32 pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left;
 
-    if ((pixels -= 2*SYSMETRICS_CXVSCROLL) <= 0) return infoPtr->MinVal;
+    if ((pixels -= 2*(SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP)) <= 0)
+        return infoPtr->MinVal;
 
     if (infoPtr->Page)
     {
@@ -249,9 +263,9 @@
     }
     else thumbSize = SYSMETRICS_CXVSCROLL;
 
-    if ((pixels -= thumbSize + 1) <= 0) return infoPtr->MinVal;
+    if ((pixels -= thumbSize) <= 0) return infoPtr->MinVal;
 
-    pos = MAX( 0, pos - SYSMETRICS_CXVSCROLL );
+    pos = MAX( 0, pos - (SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP) );
     if (pos > pixels) pos = pixels;
 
     if (!infoPtr->Page) pos *= infoPtr->MaxVal - infoPtr->MinVal;
@@ -277,22 +291,22 @@
 
     if (vertical)
     {
-        if (pt.y <= rect.top + arrowSize + 1) return SCROLL_TOP_ARROW;
+        if (pt.y < rect.top + arrowSize) return SCROLL_TOP_ARROW;
         if (pt.y >= rect.bottom - arrowSize) return SCROLL_BOTTOM_ARROW;
         if (!thumbPos) return SCROLL_TOP_RECT;
         pt.y -= rect.top;
         if (pt.y < thumbPos) return SCROLL_TOP_RECT;
-        if (pt.y > thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
+        if (pt.y >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
         return SCROLL_THUMB;
     }
     else  /* horizontal */
     {
-        if (pt.x <= rect.left + arrowSize) return SCROLL_TOP_ARROW;
+        if (pt.x < rect.left + arrowSize) return SCROLL_TOP_ARROW;
         if (pt.x >= rect.right - arrowSize) return SCROLL_BOTTOM_ARROW;
         if (!thumbPos) return SCROLL_TOP_RECT;
         pt.x -= rect.left;
         if (pt.x < thumbPos) return SCROLL_TOP_RECT;
-        if (pt.x > thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
+        if (pt.x >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
         return SCROLL_THUMB;
     }
 }
@@ -313,26 +327,26 @@
                                     : LEFT_ARROW(infoPtr->flags, top_pressed));
     SetStretchBltMode32( hdc, STRETCH_DELETESCANS );
     StretchBlt32( hdc, rect->left, rect->top,
-                  vertical ? rect->right-rect->left : arrowSize+1,
-                  vertical ? arrowSize+1 : rect->bottom-rect->top,
+                  vertical ? rect->right-rect->left : arrowSize,
+                  vertical ? arrowSize : rect->bottom-rect->top,
                   hdcMem, 0, 0,
-                  SYSMETRICS_CXVSCROLL + 1, SYSMETRICS_CYHSCROLL + 1,
+                  SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL,
                   SRCCOPY );
 
     SelectObject32( hdcMem, vertical ?
                     BOTTOM_ARROW( infoPtr->flags, bottom_pressed )
                     : RIGHT_ARROW( infoPtr->flags, bottom_pressed ) );
     if (vertical)
-        StretchBlt32( hdc, rect->left, rect->bottom - arrowSize - 1,
-                      rect->right - rect->left, arrowSize + 1,
+        StretchBlt32( hdc, rect->left, rect->bottom - arrowSize,
+                      rect->right - rect->left, arrowSize,
                       hdcMem, 0, 0,
-                      SYSMETRICS_CXVSCROLL + 1, SYSMETRICS_CYHSCROLL + 1,
+                      SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL,
                       SRCCOPY );
     else
-        StretchBlt32( hdc, rect->right - arrowSize - 1, rect->top,
-                      arrowSize + 1, rect->bottom - rect->top,
+        StretchBlt32( hdc, rect->right - arrowSize, rect->top,
+                      arrowSize, rect->bottom - rect->top,
                       hdcMem, 0, 0,
-                      SYSMETRICS_CXVSCROLL + 1, SYSMETRICS_CYHSCROLL + 1,
+                      SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL,
                       SRCCOPY );
     SelectObject32( hdcMem, hbmpPrev );
     DeleteDC32( hdcMem );
@@ -351,20 +365,25 @@
     if (vertical)
     {
         r.top += SCROLL_TrackingPos;
-        if (r.top < rect->top + arrowSize) r.top = rect->top + arrowSize;
-        if (r.top + thumbSize >= rect->bottom - arrowSize)
-            r.top = rect->bottom - arrowSize - thumbSize - 1;
-        r.bottom = r.top + thumbSize + 1;
+        if (r.top < rect->top + arrowSize - SCROLL_ARROW_THUMB_OVERLAP)
+	    r.top = rect->top + arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
+        if (r.top + thumbSize >
+	               rect->bottom - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP))
+            r.top = rect->bottom - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP)
+	                                                          - thumbSize;
+        r.bottom = r.top + thumbSize;
     }
     else
     {
         r.left += SCROLL_TrackingPos;
-        if (r.left < rect->left + arrowSize) r.left = rect->left + arrowSize;
-        if (r.left + thumbSize >= rect->right - arrowSize)
-            r.left = rect->right - arrowSize - thumbSize - 1;
-        r.right = r.left + thumbSize + 1;
+        if (r.left < rect->left + arrowSize - SCROLL_ARROW_THUMB_OVERLAP)
+	    r.left = rect->left + arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
+        if (r.left + thumbSize >
+	               rect->right - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP))
+            r.left = rect->right - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) 
+	                                                          - thumbSize;
+        r.right = r.left + thumbSize;
     }
-    InflateRect32( &r, -1, -1 );
     DrawFocusRect32( hdc, &r );
     SCROLL_MovingThumb = !SCROLL_MovingThumb;
 }
@@ -407,15 +426,13 @@
     r = *rect;
     if (vertical)
     {
-        r.top    += arrowSize - 1;
-        r.bottom -= arrowSize;
-	r.right--;
+        r.top    += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
+        r.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
     }
     else
     {
-        r.left  += arrowSize - 1;
-        r.right -= arrowSize;
-	r.bottom--;
+        r.left  += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
+        r.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
     }
 
       /* Draw the scroll bar frame */
@@ -435,27 +452,27 @@
     {
         PatBlt32( hdc, r.left + 1, r.top + 1,
                   r.right - r.left - 2,
-                  thumbPos - arrowSize,
+                  thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) - 1,
                   top_selected ? 0x0f0000 : PATCOPY );
-        r.top += thumbPos - arrowSize;
-        PatBlt32( hdc, r.left + 1, r.top + thumbSize + 1,
+        r.top += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
+        PatBlt32( hdc, r.left + 1, r.top + thumbSize,
                   r.right - r.left - 2,
-                  r.bottom - r.top - thumbSize - 2,
+                  r.bottom - r.top - thumbSize - 1,
                   bottom_selected ? 0x0f0000 : PATCOPY );
-        r.bottom = r.top + thumbSize + 2;
+        r.bottom = r.top + thumbSize;
     }
     else  /* horizontal */
     {
         PatBlt32( hdc, r.left + 1, r.top + 1,
-                  thumbPos - arrowSize,
+                  thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) - 1,
                   r.bottom - r.top - 2,
                   top_selected ? 0x0f0000 : PATCOPY );
-        r.left += thumbPos - arrowSize;
-        PatBlt32( hdc, r.left + thumbSize + 1, r.top + 1,
-                  r.right - r.left - thumbSize - 2,
+        r.left += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
+        PatBlt32( hdc, r.left + thumbSize, r.top + 1,
+                  r.right - r.left - thumbSize - 1,
                   r.bottom - r.top - 2,
                   bottom_selected ? 0x0f0000 : PATCOPY );
-        r.right = r.left + thumbSize + 2;
+        r.right = r.left + thumbSize;
     }
 
       /* Draw the thumb */
@@ -493,6 +510,7 @@
 
     vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
                                         &arrowSize, &thumbSize, &thumbPos );
+
       /* Draw the arrows */
 
     if (arrows && arrowSize) SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize,
diff --git a/controls/status.c b/controls/status.c
index a24a47b..6df39b0 100644
--- a/controls/status.c
+++ b/controls/status.c
@@ -103,9 +103,19 @@
     /* now draw text */
     if (text) {
       int oldbkmode = SetBkMode32(hdc, TRANSPARENT);
+      LPSTR p = text;
+      UINT32 align = DT_LEFT;
+      if (*p == '\t') {
+	p++;
+	align = DT_CENTER;
+
+	if (*p == '\t') {
+	  p++;
+	  align = DT_RIGHT;
+	}
+      }
       r.left += 3;
-      DrawText32A(hdc, text, lstrlen32A(text),
-		  &r, DT_LEFT|DT_VCENTER|DT_SINGLELINE);  
+      DrawText32A(hdc, p, lstrlen32A(p), &r, align|DT_VCENTER|DT_SINGLELINE);
       if (oldbkmode != TRANSPARENT)
 	SetBkMode32(hdc, oldbkmode);
     }
@@ -118,6 +128,7 @@
     int      i;
     RECT32   rect;
     HBRUSH32 hbrBk;
+    HFONT32 hOldFont;
     WND *wndPtr;
 
     wndPtr = WIN_FindWndPtr(hwnd);
@@ -134,6 +145,8 @@
 	hbrBk = GetSysColorBrush32 (COLOR_3DFACE);
     FillRect32(hdc, &rect, hbrBk);
 
+    hOldFont = SelectObject32 (hdc, self->hFont ? self->hFont : self->hDefaultFont);
+
     if (self->simple) {
 	SB_DrawPart (hdc,
 		     &self->part0.bound,
@@ -165,6 +178,8 @@
 	}
     }
 
+    SelectObject32 (hdc, hOldFont);
+
     if (self->clrBk != CLR_DEFAULT)
 	DeleteObject32 (hbrBk);
 
@@ -252,6 +267,7 @@
 	}
     }
     InvalidateRect32(hwnd, &part->bound, FALSE);
+//    SW_RefreshPart (hdc, part);
     return TRUE;
 }
 
@@ -320,9 +336,10 @@
 static LRESULT
 SW_Create(HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
 {
-    RECT32	rect;
     LPCREATESTRUCT32A lpCreate = (LPCREATESTRUCT32A) lParam;
-    int	height, width, len;
+    NONCLIENTMETRICS32A nclm;
+    RECT32	rect;
+    int	        width, len;
     HDC32	hdc;
     HWND32	parent;
     WND *wndPtr;
@@ -331,7 +348,6 @@
     wndPtr = WIN_FindWndPtr(hwnd);
     self = (STATUSWINDOWINFO*)HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY,
 					 sizeof(STATUSWINDOWINFO));
-
     wndPtr->wExtra[0] = (DWORD)self;
 
     self->numParts = 1;
@@ -341,6 +357,10 @@
     self->hFont = 0;
     GetClientRect32(hwnd, &rect);
 
+    nclm.cbSize = sizeof(NONCLIENTMETRICS32A);
+    SystemParametersInfo32A (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
+    self->hDefaultFont = CreateFontIndirect32A (&nclm.lfStatusFont);
+
     /* initialize simple case */
     self->part0.bound = rect;
     self->part0.text = 0;
@@ -362,11 +382,14 @@
         lstrcpy32A (self->parts[0].text, lpCreate->lpszName);
     }
 
-    height = 20;
     if ((hdc = GetDC32 (0))) {
 	TEXTMETRIC32A tm;
+	HFONT32 hOldFont;
+
+	hOldFont = SelectObject32 (hdc,self->hDefaultFont);
 	GetTextMetrics32A(hdc, &tm);
 	self->textHeight = tm.tmHeight;
+	SelectObject32 (hdc, hOldFont);
 	ReleaseDC32(0, hdc);
     }
 
@@ -554,6 +577,11 @@
     if (self->part0.text && (self->part0.style != SBT_OWNERDRAW))
 	HeapFree(SystemHeap, 0, self->part0.text);
     HeapFree(SystemHeap, 0, self->parts);
+
+    /* delete default font */
+    if (self->hDefaultFont)
+	DeleteObject32 (self->hDefaultFont);
+
     HeapFree(SystemHeap, 0, self);
     return 0;
 }
@@ -673,6 +701,7 @@
         lstrcpy32A (part->text, (LPCSTR)lParam);
     }
     InvalidateRect32(hwnd, &part->bound, FALSE);
+//    SW_RefreshPart (hdc, part);
 
     return TRUE;
 }
diff --git a/controls/toolbar.c b/controls/toolbar.c
index 86a1e6c..3c5d134 100644
--- a/controls/toolbar.c
+++ b/controls/toolbar.c
@@ -13,7 +13,9 @@
  * TODO:
  *   - Many messages.
  *   - All notifications.
- *   - Tooltip support.
+ *   - Fix TB_GETBITMAPFLAGS.
+ *   - Fix TB_GETROWS and TB_SETROWS.
+ *   - Tooltip support (partially).
  *   - Unicode suppport.
  *   - Internal COMMCTL32 bitmaps.
  *   - Customize dialog.
@@ -30,14 +32,15 @@
 
 #include "windows.h"
 #include "commctrl.h"
+#include "cache.h"
 #include "toolbar.h"
 #include "heap.h"
 #include "win.h"
 #include "debug.h"
 
 
-#define SEPARATOR_WIDTH  12
-
+#define SEPARATOR_WIDTH  8
+#define SEPARATOR_HEIGHT 5
 
 
 
@@ -60,10 +63,15 @@
     else {
 	if (!(btnPtr->fsState & TBSTATE_ENABLED)) {
 	    /* button is disabled */
+	    HICON32 hIcon;
 	    DrawEdge32 (hdc, &rc, EDGE_RAISED,
 			BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
-	    ImageList_Draw (infoPtr->himlDis, btnPtr->iBitmap, hdc,
-			    rc.left+2, rc.top+2, ILD_NORMAL);
+	    hIcon = ImageList_GetIcon (infoPtr->himlDef, btnPtr->iBitmap, ILD_IMAGE);
+	    DrawState32A (hdc, (HBRUSH32)NULL, NULL, MAKELONG(hIcon, 0), 0,
+		rc.left+1, rc.top+1,
+		infoPtr->nBitmapWidth, infoPtr->nBitmapHeight, DST_ICON|DSS_DISABLED);
+//	    ImageList_Draw (infoPtr->himlDis, btnPtr->iBitmap, hdc,
+//			    rc.left+1, rc.top+1, ILD_NORMAL);
 	    return;
 	}
 
@@ -72,15 +80,44 @@
 	    DrawEdge32 (hdc, &rc, EDGE_SUNKEN,
 			BF_RECT | BF_MIDDLE | BF_ADJUST);
 	    ImageList_Draw (infoPtr->himlDef, btnPtr->iBitmap, hdc,
-			    rc.left+3, rc.top+3, ILD_NORMAL);
+			    rc.left+2, rc.top+2, ILD_NORMAL);
 	    return;
 	}
-	else {
-	    DrawEdge32 (hdc, &rc, EDGE_RAISED,
-			BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
+
+	if ((btnPtr->fsStyle & TBSTYLE_CHECK) &&
+	    (btnPtr->fsState & TBSTATE_CHECKED)) {
+	    HBRUSH32 hbr;
+	    DrawEdge32 (hdc, &rc, EDGE_SUNKEN,
+			BF_RECT | BF_MIDDLE | BF_ADJUST);
+
+	    hbr = SelectObject32 (hdc, CACHE_GetPattern55AABrush ());
+	    PatBlt32 (hdc, rc.left, rc.top, rc.right - rc.left,
+		      rc.bottom - rc.top, 0x00FA0089);
+	    SelectObject32 (hdc, hbr);
 	    ImageList_Draw (infoPtr->himlDef, btnPtr->iBitmap, hdc,
 			    rc.left+2, rc.top+2, ILD_NORMAL);
+	    return;
 	}
+	
+	if (btnPtr->fsState & TBSTATE_INDETERMINATE) {
+	    HBRUSH32 hbr;
+	    DrawEdge32 (hdc, &rc, EDGE_RAISED,
+			BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
+
+	    hbr = SelectObject32 (hdc, CACHE_GetPattern55AABrush ());
+	    PatBlt32 (hdc, rc.left, rc.top, rc.right - rc.left,
+		      rc.bottom - rc.top, 0x00FA0089);
+	    SelectObject32 (hdc, hbr);
+//	    ImageList_Draw (infoPtr->himlDef, btnPtr->iBitmap, hdc,
+//			    rc.left+1, rc.top+1, ILD_NORMAL);
+	    return;
+	}
+
+	/* normal state */
+	DrawEdge32 (hdc, &rc, EDGE_RAISED,
+		    BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
+	ImageList_Draw (infoPtr->himlDef, btnPtr->iBitmap, hdc,
+			rc.left+1, rc.top+1, ILD_NORMAL);
     }
 }
 
@@ -134,6 +171,8 @@
 	    btnPtr->rect.right = btnPtr->rect.left + infoPtr->nButtonWidth;
 	rect.left = btnPtr->rect.right;
     }
+
+    infoPtr->nHeight = rect.bottom + 8;
 }
 
 
@@ -149,13 +188,13 @@
     for (i = 0; i < infoPtr->nNumButtons; i++) {
 	if (btnPtr->fsStyle & TBSTYLE_SEP) {
 	    if (PtInRect32 (&btnPtr->rect, *lpPt)) {
-//		TRACE (toolbar, " ON SEPARATOR %d!\n", i);
+		TRACE (toolbar, " ON SEPARATOR %d!\n", i);
 		return -i;
 	    }
 	}
 	else {
 	    if (PtInRect32 (&btnPtr->rect, *lpPt)) {
-//		TRACE (toolbar, " ON BUTTON %d!\n", i);
+		TRACE (toolbar, " ON BUTTON %d!\n", i);
 		return i;
 	    }
 
@@ -164,7 +203,7 @@
 	btnPtr++;
     }
 
-//    TRACE (toolbar, " NOWHERE!\n");
+    TRACE (toolbar, " NOWHERE!\n");
     return -1;
 }
 
@@ -177,10 +216,59 @@
 
     btnPtr = infoPtr->buttons;
     for (i = 0; i < infoPtr->nNumButtons; i++) {
-	if (btnPtr->idCommand == idCommand)
+	if (btnPtr->idCommand == idCommand) {
+	    TRACE (toolbar, "command=%d index=%d\n", idCommand, i);
 	    return i;
+	}
 	btnPtr++;
     }
+    TRACE (toolbar, "no index found for command=%d\n", idCommand);
+    return -1;
+}
+
+
+static INT32
+TOOLBAR_GetCheckedGroupButtonIndex (TOOLBAR_INFO *infoPtr, INT32 nIndex)
+{
+    TBUTTON_INFO *btnPtr;
+    INT32 nRunIndex;
+
+    if ((nIndex < 0) || (nIndex > infoPtr->nNumButtons))
+	return -1;
+
+    /* check index button */
+    btnPtr = &infoPtr->buttons[nIndex];
+    if ((btnPtr->fsStyle & TBSTYLE_CHECKGROUP) == TBSTYLE_CHECKGROUP) {
+	if (btnPtr->fsState & TBSTATE_CHECKED)
+	    return nIndex;
+    }
+
+    /* check previous buttons */
+    nRunIndex = nIndex - 1;
+    while (nRunIndex >= 0) {
+	btnPtr = &infoPtr->buttons[nRunIndex];
+	if ((btnPtr->fsStyle & TBSTYLE_CHECKGROUP) == TBSTYLE_CHECKGROUP) {
+	    if (btnPtr->fsState & TBSTATE_CHECKED)
+		return nRunIndex;
+	}
+	else
+	    break;
+	nRunIndex--;
+    }
+
+    /* check next buttons */
+    nRunIndex = nIndex + 1;
+    while (nRunIndex < infoPtr->nNumButtons) {
+	btnPtr = &infoPtr->buttons[nRunIndex];	
+	if ((btnPtr->fsStyle & TBSTYLE_CHECKGROUP) == TBSTYLE_CHECKGROUP) {
+	    if (btnPtr->fsState & TBSTATE_CHECKED)
+		return nRunIndex;
+	}
+	else
+	    break;
+	nRunIndex++;
+    }
+
     return -1;
 }
 
@@ -190,6 +278,7 @@
 {
     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
     LPTBADDBITMAP lpAddBmp = (LPTBADDBITMAP)lParam;
+    INT32 nIndex = 0;
 
     if ((!lpAddBmp) || ((INT32)wParam <= 0))
 	return -1;
@@ -205,6 +294,7 @@
 			      (INT32)wParam, 2);
     }
 
+#if 0
     if (!(infoPtr->himlDis)) {
 	/* create new disabled image list */
 	TRACE (toolbar, "creating disabled image list!\n");
@@ -213,12 +303,14 @@
 			      infoPtr->nBitmapHeight, ILC_COLOR | ILC_MASK,
 			      (INT32)wParam, 2);
     }
-
+#endif
 
     /* Add bitmaps to the default image list */
     if (lpAddBmp->hInst == (HINSTANCE32)0) {
-
-	ImageList_Add (infoPtr->himlDef, (HBITMAP32)lpAddBmp->nID, 0);
+	nIndex = 
+	    ImageList_AddMasked (infoPtr->himlDef, (HBITMAP32)lpAddBmp->nID,
+				 0xC0C0C0);
+//				 GetSysColor32 (COLOR_3DFACE));
     }
     else if (lpAddBmp->hInst == HINST_COMMCTRL) {
 	/* add internal bitmaps */
@@ -226,23 +318,22 @@
 
 	/* Hack to "add" some reserved images within the image list 
 	   to get the right image indices */
-	ImageList_SetImageCount (infoPtr->himlDef,
-	    ImageList_GetImageCount (infoPtr->himlDef) + (INT32)wParam);
+	nIndex = ImageList_GetImageCount (infoPtr->himlDef);
+	ImageList_SetImageCount (infoPtr->himlDef, nIndex + (INT32)wParam);
     }
     else {
 	HBITMAP32 hBmp =
 	    LoadBitmap32A (lpAddBmp->hInst, (LPSTR)lpAddBmp->nID);
 
-	ImageList_Add (infoPtr->himlDef, hBmp, (HBITMAP32)0);
+	nIndex = ImageList_Add (infoPtr->himlDef, hBmp, (HBITMAP32)0);
 
 	DeleteObject32 (hBmp); 
     }
 
 
-    /* Add bitmaps to the disabled image list */
+    infoPtr->nNumBitmaps += (INT32)wParam;
 
-
-    return 0;
+    return nIndex;
 }
 
 
@@ -297,8 +388,95 @@
 }
 
 
-// << TOOLBAR_AddString32A >>
-// << TOOLBAR_AutoSize >>
+// << TOOLBAR_AddButtons32W >>
+
+
+static LRESULT
+TOOLBAR_AddString32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+    INT32 nIndex;
+
+    if (wParam) {
+	char szString[256];
+	INT32 len;
+	TRACE (toolbar, "adding string from resource!\n");
+
+	len = LoadString32A ((HINSTANCE32)wParam, (UINT32)lParam,
+			     szString, 256);
+
+	TRACE (toolbar, "len=%d\n", len);
+	nIndex = infoPtr->nNumStrings;
+	if (infoPtr->nNumStrings == 0) {
+	    infoPtr->strings =
+		HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY, sizeof(char *));
+	}
+	else {
+	    char **oldStrings = infoPtr->strings;
+	    infoPtr->strings =
+		HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY,
+			   sizeof(char *) * (infoPtr->nNumStrings + 1));
+	    memcpy (&infoPtr->strings[0], &oldStrings[0],
+		    sizeof(char *) * infoPtr->nNumStrings);
+	    HeapFree (SystemHeap, 0, oldStrings);
+	}
+
+	infoPtr->strings[infoPtr->nNumStrings] =
+	    HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY, sizeof(char)*(len+1));
+	lstrcpy32A (infoPtr->strings[infoPtr->nNumStrings], szString);
+	infoPtr->nNumStrings++;
+    }
+    else {
+	char *p = (char*)lParam;
+	INT32 len;
+
+	if (p == NULL) return -1;
+	TRACE (toolbar, "adding string(s) from array!\n");
+	nIndex = infoPtr->nNumStrings;
+	while (*p) {
+	    len = lstrlen32A (p);
+	    TRACE (toolbar, "len=%d\n", len);
+
+	    if (infoPtr->nNumStrings == 0) {
+		infoPtr->strings =
+		    HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY, sizeof(char *));
+	    }
+	    else {
+		char **oldStrings = infoPtr->strings;
+		infoPtr->strings =
+		    HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY,
+			       sizeof(char *) * (infoPtr->nNumStrings + 1));
+		memcpy (&infoPtr->strings[0], &oldStrings[0],
+			sizeof(char *) * infoPtr->nNumStrings);
+		HeapFree (SystemHeap, 0, oldStrings);
+	    }
+
+	    infoPtr->strings[infoPtr->nNumStrings] =
+		HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY, sizeof(char)*(len+1));
+	    lstrcpy32A (infoPtr->strings[infoPtr->nNumStrings], p);
+	    infoPtr->nNumStrings++;
+
+	    p += (len+1);
+	}
+
+    }
+
+    return nIndex;
+}
+
+
+// << TOOLBAR_AddString32W >>
+
+
+static LRESULT
+TOOLBAR_AutoSize (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+
+    TRACE (toolbar, "auto size!\n");
+
+    return 0;
+}
 
 
 static LRESULT
@@ -344,7 +522,6 @@
 }
 
 
-/*
 static LRESULT
 TOOLBAR_CheckButton (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
@@ -352,24 +529,41 @@
     TBUTTON_INFO *btnPtr;
     HDC32 hdc;
     INT32 nIndex;
+    INT32 nOldIndex = -1;
 
     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT32)wParam);
     if (nIndex == -1)
 	return FALSE;
 
     btnPtr = &infoPtr->buttons[nIndex];
+
+    if (!(btnPtr->fsStyle & TBSTYLE_CHECK))
+	return FALSE;
+
     if (LOWORD(lParam) == FALSE)
 	btnPtr->fsState &= ~TBSTATE_CHECKED;
-    else
+    else {
+	if (btnPtr->fsStyle & TBSTYLE_GROUP) {
+	    nOldIndex = 
+		TOOLBAR_GetCheckedGroupButtonIndex (infoPtr, nIndex);
+	    if (nOldIndex == nIndex)
+		return 0;
+	    if (nOldIndex != -1)
+		infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED;
+	}
 	btnPtr->fsState |= TBSTATE_CHECKED;
+    }
 
     hdc = GetDC32 (wndPtr->hwndSelf);
+    if (nOldIndex != -1)
+	TOOLBAR_DrawButton (wndPtr, &infoPtr->buttons[nOldIndex], hdc);
     TOOLBAR_DrawButton (wndPtr, btnPtr, hdc);
     ReleaseDC32 (wndPtr->hwndSelf, hdc);
 
+    /* FIXME: Send a WM_COMMAND or WM_NOTIFY */
+
     return TRUE;
 }
-*/
 
 
 static LRESULT
@@ -388,9 +582,9 @@
 TOOLBAR_DeleteButton (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
-    INT32 iIndex = (INT32)wParam;
+    INT32 nIndex = (INT32)wParam;
 
-    if ((iIndex < 0) || (iIndex >= infoPtr->nNumButtons))
+    if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
 	return FALSE;
 
     if (infoPtr->nNumButtons == 1) {
@@ -400,9 +594,23 @@
 	infoPtr->nNumButtons = 0;
     }
     else {
+	TBUTTON_INFO *oldButtons = infoPtr->buttons;
+        TRACE(toolbar, "complex delete! [nIndex=%d]\n", nIndex);
 
-        TRACE(header, "complex delete! [iIndex=%d]\n", iIndex);
+	infoPtr->nNumButtons--;
+	infoPtr->buttons = HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY,
+				      sizeof (TBUTTON_INFO) * infoPtr->nNumButtons);
+        if (nIndex > 0) {
+            memcpy (&infoPtr->buttons[0], &oldButtons[0],
+                    nIndex * sizeof(TBUTTON_INFO));
+        }
 
+        if (nIndex < infoPtr->nNumButtons) {
+            memcpy (&infoPtr->buttons[nIndex], &oldButtons[nIndex+1],
+                    (infoPtr->nNumButtons - nIndex) * sizeof(TBUTTON_INFO));
+        }
+
+        HeapFree (SystemHeap, 0, oldButtons);
     }
 
     TOOLBAR_CalcToolbar (wndPtr);
@@ -457,9 +665,164 @@
 }
 
 
-// << TOOLBAR_GetBitmapFlags >>
-// << TOOLBAR_GetButton >>
-// << ... >>
+static LRESULT
+TOOLBAR_GetBitmapFlags (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    FIXME (toolbar, "stub!\n");
+    return 0;
+}
+
+
+static LRESULT
+TOOLBAR_GetButton (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+    LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
+    INT32 nIndex = (INT32)wParam;
+    TBUTTON_INFO *btnPtr;
+
+    if (infoPtr == NULL) return FALSE;
+    if (lpTbb == NULL) return FALSE;
+
+    if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
+	return FALSE;
+
+    btnPtr = &infoPtr->buttons[nIndex];
+    lpTbb->iBitmap   = btnPtr->iBitmap;
+    lpTbb->idCommand = btnPtr->idCommand;
+    lpTbb->fsState   = btnPtr->fsState;
+    lpTbb->fsStyle   = btnPtr->fsStyle;
+    lpTbb->dwData    = btnPtr->dwData;
+    lpTbb->iString   = btnPtr->iString;
+
+    return TRUE;
+}
+
+
+// << TOOLBAR_GetButtonInfo >>
+// << TOOLBAR_GetButtonSize >>
+
+
+static LRESULT
+TOOLBAR_GetButtonText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+    INT32 nIndex, nStringIndex;
+
+    nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT32)wParam);
+    if (nIndex == -1)
+	return -1;
+
+    nStringIndex = infoPtr->buttons[nIndex].iString;
+
+    TRACE (toolbar, "index=%d stringIndex=%d\n", nIndex, nStringIndex);
+
+    if ((nStringIndex < 0) || (nStringIndex >= infoPtr->nNumStrings))
+	return -1;
+
+    if (lParam == 0) return -1;
+
+    lstrcpy32A ((LPSTR)lParam, (LPSTR)infoPtr->strings[nStringIndex]);
+
+    return lstrlen32A ((LPSTR)infoPtr->strings[nStringIndex]);
+}
+
+
+// << TOOLBAR_GetButtonText32W >>
+// << TOOLBAR_GetColorScheme >>
+// << TOOLBAR_GetDisabledImageList >>
+// << TOOLBAR_GetExtendedStyle >>
+// << TOOLBAR_GetHotImageList >>
+// << TOOLBAR_GetHotItem >>
+// << TOOLBAR_GetImageList >>
+// << TOOLBAR_GetInsertMark >>
+// << TOOLBAR_GetInsertMarkColor >>
+
+
+static LRESULT
+TOOLBAR_GetItemRect (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+    TBUTTON_INFO *btnPtr;
+    LPRECT32     lpRect;
+    INT32        nIndex;
+
+    if (infoPtr == NULL) return FALSE;
+    nIndex = (INT32)wParam;
+    btnPtr = &infoPtr->buttons[nIndex];
+    if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
+	return FALSE;
+    lpRect = (LPRECT32)lParam;
+    if (lpRect == NULL) return FALSE;
+    if (btnPtr->fsState & TBSTATE_HIDDEN) return FALSE;
+    
+    lpRect->left   = btnPtr->rect.left;
+    lpRect->right  = btnPtr->rect.right;
+    lpRect->bottom = btnPtr->rect.bottom;
+    lpRect->top    = btnPtr->rect.top;
+
+    return TRUE;
+}
+
+
+// << TOOLBAR_GetMaxSize >>
+// << TOOLBAR_GetObject >>
+// << TOOLBAR_GetPadding >>
+// << TOOLBAR_GetRect >>
+
+
+static LRESULT
+TOOLBAR_GetRows (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+
+    if (wndPtr->dwStyle & TBSTYLE_WRAPABLE)
+	return infoPtr->nMaxRows;
+    else
+	return 1;
+}
+
+
+static LRESULT
+TOOLBAR_GetState (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+    INT32 nIndex;
+
+    nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT32)wParam);
+    if (nIndex == -1) return -1;
+
+    return infoPtr->buttons[nIndex].fsState;
+}
+
+
+static LRESULT
+TOOLBAR_GetStyle (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+    INT32 nIndex;
+
+    nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT32)wParam);
+    if (nIndex == -1) return -1;
+
+    return infoPtr->buttons[nIndex].fsStyle;
+}
+
+
+// << TOOLBAR_GetTextRows >>
+
+
+static LRESULT
+TOOLBAR_GetToolTips (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+
+    if (infoPtr == NULL) return 0;
+    return infoPtr->hwndToolTip;
+}
+
+
+// << TOOLBAR_GetUnicodeFormat >>
 
 
 static LRESULT
@@ -496,6 +859,90 @@
 
 
 static LRESULT
+TOOLBAR_Indeterminate (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+    TBUTTON_INFO *btnPtr;
+    HDC32 hdc;
+    INT32 nIndex;
+
+    nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT32)wParam);
+    if (nIndex == -1)
+	return FALSE;
+
+    btnPtr = &infoPtr->buttons[nIndex];
+    if (LOWORD(lParam) == FALSE)
+	btnPtr->fsState &= ~TBSTATE_INDETERMINATE;
+    else
+	btnPtr->fsState |= TBSTATE_INDETERMINATE;
+
+    hdc = GetDC32 (wndPtr->hwndSelf);
+    TOOLBAR_DrawButton (wndPtr, btnPtr, hdc);
+    ReleaseDC32 (wndPtr->hwndSelf, hdc);
+
+    return TRUE;
+}
+
+
+static LRESULT
+TOOLBAR_InsertButton32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+    LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
+    INT32 nIndex = (INT32)wParam;
+    TBUTTON_INFO *oldButtons;
+    HDC32 hdc;
+
+    if (lpTbb == NULL) return FALSE;
+    if (nIndex < 0) return FALSE;
+
+    TRACE (toolbar, "inserting button index=%d\n", nIndex);
+    if (nIndex > infoPtr->nNumButtons) {
+	nIndex = infoPtr->nNumButtons;
+	TRACE (toolbar, "adjust index=%d\n", nIndex);
+    }
+
+    oldButtons = infoPtr->buttons;
+    infoPtr->nNumButtons++;
+    infoPtr->buttons = HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY,
+				  sizeof (TBUTTON_INFO) * infoPtr->nNumButtons);
+    /* pre insert copy */
+    if (nIndex > 0) {
+	memcpy (&infoPtr->buttons[0], &oldButtons[0],
+		nIndex * sizeof(TBUTTON_INFO));
+    }
+
+    /* insert new button */
+    infoPtr->buttons[nIndex].iBitmap   = lpTbb->iBitmap;
+    infoPtr->buttons[nIndex].idCommand = lpTbb->idCommand;
+    infoPtr->buttons[nIndex].fsState   = lpTbb->fsState;
+    infoPtr->buttons[nIndex].fsStyle   = lpTbb->fsStyle;
+    infoPtr->buttons[nIndex].dwData    = lpTbb->dwData;
+    infoPtr->buttons[nIndex].iString   = lpTbb->iString;
+
+    /* post insert copy */
+    if (nIndex < infoPtr->nNumButtons - 1) {
+	memcpy (&infoPtr->buttons[nIndex+1], &oldButtons[nIndex],
+		(infoPtr->nNumButtons - nIndex - 1) * sizeof(TBUTTON_INFO));
+    }
+
+    HeapFree (SystemHeap, 0, oldButtons);
+
+    TOOLBAR_CalcToolbar (wndPtr);
+
+    hdc = GetDC32 (wndPtr->hwndSelf);
+    TOOLBAR_Refresh (wndPtr, hdc);
+    ReleaseDC32 (wndPtr->hwndSelf, hdc);
+
+    return TRUE;
+}
+
+
+// << TOOLBAR_InsertButton32W >>
+// << TOOLBAR_InsertMarkHitTest >>
+
+
+static LRESULT
 TOOLBAR_IsButtonChecked (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
@@ -615,6 +1062,7 @@
 // << TOOLBAR_SaveRestore >>
 // << TOOLBAR_SetAnchorHighlight >>
 
+
 static LRESULT
 TOOLBAR_SetBitmapSize (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
@@ -666,6 +1114,14 @@
 }
 
 
+// << TOOLBAR_SetColorScheme >>
+// << TOOLBAR_SetDisabledImageList >>
+// << TOOLBAR_SetDrawTextFlags >>
+// << TOOLBAR_SetExtendedStyle >>
+// << TOOLBAR_SetHotImageList >>
+// << TOOLBAR_SetHotItem >>
+// << TOOLBAR_SetImageList >>
+
 
 static LRESULT
 TOOLBAR_SetIndent (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
@@ -683,6 +1139,36 @@
 }
 
 
+// << TOOLBAR_SetInsertMark >>
+// << TOOLBAR_SetInsertMarkColor >>
+// << TOOLBAR_SetMaxTextRows >>
+// << TOOLBAR_SetPadding >>
+
+
+static LRESULT
+TOOLBAR_SetParent (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+    HWND32 hwndOldNotify;
+
+    if (infoPtr == NULL) return 0;
+    hwndOldNotify = infoPtr->hwndNotify;
+    infoPtr->hwndNotify = (HWND32)wParam;
+
+    return hwndOldNotify;
+}
+
+
+static LRESULT
+TOOLBAR_SetRows (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+
+    FIXME (toolbar, "support multiple rows!\n");
+
+    return 0;
+}
+
 
 static LRESULT
 TOOLBAR_SetState (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
@@ -730,7 +1216,17 @@
 }
 
 
-// << TOOLBAR_SetToolTips >>
+static LRESULT
+TOOLBAR_SetToolTips (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+
+    if (infoPtr == NULL) return 0;
+    infoPtr->hwndToolTip = (HWND32)wParam;
+    return 0;
+}
+
+
 // << TOOLBAR_SetUnicodeFormat >>
 
 
@@ -744,18 +1240,27 @@
                                    sizeof(TOOLBAR_INFO));
     wndPtr->wExtra[0] = (DWORD)infoPtr;
 
+    if (infoPtr == NULL) {
+	ERR (toolbar, "could not allocate info memory!\n");
+	return 0;
+    }
+
+    /* initialize info structure */
     infoPtr->nButtonHeight = 22;
-    infoPtr->nButtonWidth = 24;
+    infoPtr->nButtonWidth = 23;
     infoPtr->nButtonTop = 2;
     infoPtr->nBitmapHeight = 15;
     infoPtr->nBitmapWidth = 16;
 
     infoPtr->nHeight = infoPtr->nButtonHeight + 6;
+    infoPtr->nMaxRows = 1;
 
     infoPtr->bCaptured = 0;
     infoPtr->nButtonDown = -1;
     infoPtr->nOldHit = -1;
 
+    infoPtr->hwndNotify = GetParent32 (wndPtr->hwndSelf);
+
     return 0;
 }
 
@@ -765,10 +1270,24 @@
 {
     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
 
+    /* delete tool tip */
+    if (infoPtr->hwndToolTip)
+	DestroyWindow32 (infoPtr->hwndToolTip);
+
     /* delete button data */
     if (infoPtr->buttons)
 	HeapFree (SystemHeap, 0, infoPtr->buttons);
 
+    /* delete strings */
+    if (infoPtr->strings) {
+	INT32 i;
+	for (i = 0; i < infoPtr->nNumStrings; i++)
+	    if (infoPtr->strings[i])
+		HeapFree (SystemHeap, 0, infoPtr->strings[i]);
+
+	HeapFree (SystemHeap, 0, infoPtr->strings);
+    }
+
     /* destroy default image list */
     if (infoPtr->himlDef)
 	ImageList_Destroy (infoPtr->himlDef);
@@ -867,6 +1386,7 @@
     TBUTTON_INFO *btnPtr;
     POINT32 pt;
     INT32   nHit;
+    INT32   nOldIndex = -1;
     HDC32   hdc;
 
     pt.x = (INT32)LOWORD(lParam);
@@ -874,20 +1394,34 @@
     nHit = TOOLBAR_InternalHitTest (wndPtr, &pt);
 
     if ((infoPtr->bCaptured) && (infoPtr->nButtonDown >= 0)) {
-
+	infoPtr->bCaptured = FALSE;
+	ReleaseCapture ();
 	btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
-
-
-
-
 	btnPtr->fsState &= ~TBSTATE_PRESSED;
+
+	if (btnPtr->fsStyle & TBSTYLE_CHECK) {
+	    if (btnPtr->fsStyle & TBSTYLE_GROUP) {
+		nOldIndex = TOOLBAR_GetCheckedGroupButtonIndex (infoPtr, infoPtr->nButtonDown);
+		if (nOldIndex == infoPtr->nButtonDown)
+		    return 0;
+		if (nOldIndex != -1)
+		    infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED;
+		btnPtr->fsState |= TBSTATE_CHECKED;
+	    }
+	    else {
+		if (btnPtr->fsState & TBSTATE_CHECKED)
+		    btnPtr->fsState &= ~TBSTATE_CHECKED;
+		else
+		    btnPtr->fsState |= TBSTATE_CHECKED;
+	    }
+	}
+
 	infoPtr->nButtonDown = -1;
 	infoPtr->nOldHit = -1;
 
-	infoPtr->bCaptured = FALSE;
-	ReleaseCapture ();
-
 	hdc = GetDC32 (wndPtr->hwndSelf);
+	if (nOldIndex != -1)
+	    TOOLBAR_DrawButton (wndPtr, &infoPtr->buttons[nOldIndex], hdc);
 	TOOLBAR_DrawButton (wndPtr, btnPtr, hdc);
 	ReleaseDC32 (wndPtr->hwndSelf, hdc);
 
@@ -1047,6 +1581,7 @@
 	parent = GetParent32 (wndPtr->hwndSelf);
 	GetClientRect32(parent, &parent_rect);
         infoPtr->nWidth = parent_rect.right - parent_rect.left;
+	TOOLBAR_CalcToolbar (wndPtr);
 	MoveWindow32(wndPtr->hwndSelf, parent_rect.left, parent_rect.top, //0, 0,
 		     infoPtr->nWidth, infoPtr->nHeight, TRUE);
 //    }
@@ -1072,11 +1607,15 @@
 	case TB_ADDBUTTONS32A:
 	    return TOOLBAR_AddButtons32A (wndPtr, wParam, lParam);
 
-//	case TB_ADDSTRING32A:
-//	    return TOOLBAR_AddString32A (wndPtr, wParam, lParam);
+//	case TB_ADDBUTTONS32W:
 
-//	case TB_AUTOSIZE:
-//	    return TOOLBAR_AutoSize (wndPtr, wParam, lParam);
+	case TB_ADDSTRING32A:
+	    return TOOLBAR_AddString32A (wndPtr, wParam, lParam);
+
+//	case TB_ADDSTRING32W:
+
+	case TB_AUTOSIZE:
+	    return TOOLBAR_AutoSize (wndPtr, wParam, lParam);
 
 	case TB_BUTTONCOUNT:
 	    return TOOLBAR_ButtonCount (wndPtr, wParam, lParam);
@@ -1087,8 +1626,8 @@
 	case TB_CHANGEBITMAP:
 	    return TOOLBAR_ChangeBitmap (wndPtr, wParam, lParam);
 
-//	case TB_CHECKBUTTON:
-//	    return TOOLBAR_CheckButton (wndPtr, wParam, lParam);
+	case TB_CHECKBUTTON:
+	    return TOOLBAR_CheckButton (wndPtr, wParam, lParam);
 
 	case TB_COMMANDTOINDEX:
 	    return TOOLBAR_CommandToIndex (wndPtr, wParam, lParam);
@@ -1106,7 +1645,20 @@
 	case TB_GETBITMAP:
 	    return TOOLBAR_GetBitmap (wndPtr, wParam, lParam);
 
-//	case TB_GETBITMAPFLAGS:
+	case TB_GETBITMAPFLAGS:
+	    return TOOLBAR_GetBitmapFlags (wndPtr, wParam, lParam);
+
+	case TB_GETBUTTON:
+	    return TOOLBAR_GetButton (wndPtr, wParam, lParam);
+
+//	case TB_GETBUTTONINFO:			/* 4.71 */
+//	case TB_GETBUTTONSIZE:			/* 4.70 */
+
+	case TB_GETBUTTONTEXT32A:
+	    return TOOLBAR_GetButtonText32A (wndPtr, wParam, lParam);
+
+//	case TB_GETBUTTONTEXT32W:
+//	case TB_GETCOLORSCHEME:			/* 4.71 */
 //	case TB_GETDISABLEDIMAGELIST:		/* 4.70 */
 //	case TB_GETEXTENDEDSTYLE:		/* 4.71 */
 //	case TB_GETHOTIMAGELIST:		/* 4.70 */
@@ -1114,16 +1666,29 @@
 //	case TB_GETIMAGELIST:			/* 4.70 */
 //	case TB_GETINSERTMARK:			/* 4.71 */
 //	case TB_GETINSERTMARKCOLOR:		/* 4.71 */
-//	case TB_GETITEMRECT:
+
+	case TB_GETITEMRECT:
+	    return TOOLBAR_GetItemRect (wndPtr, wParam, lParam);
+
 //	case TB_GETMAXSIZE:			/* 4.71 */
 //	case TB_GETOBJECT:			/* 4.71 */
 //	case TB_GETPADDING:			/* 4.71 */
 //	case TB_GETRECT:			/* 4.70 */
-//	case TB_GETROWS:
-//	case TB_GETSTATE:
-//	case TB_GETSTYLE:			/* 4.70 */
+
+	case TB_GETROWS:
+	    return TOOLBAR_GetRows (wndPtr, wParam, lParam);
+
+	case TB_GETSTATE:
+	    return TOOLBAR_GetState (wndPtr, wParam, lParam);
+
+	case TB_GETSTYLE:
+	    return TOOLBAR_GetStyle (wndPtr, wParam, lParam);
+
 //	case TB_GETTEXTROWS:			/* 4.70 */
-//	case TB_GETTOOLTIPS:
+
+	case TB_GETTOOLTIPS:
+	    return TOOLBAR_GetToolTips (wndPtr, wParam, lParam);
+
 //	case TB_GETUNICODEFORMAT:
 
 	case TB_HIDEBUTTON:
@@ -1132,12 +1697,13 @@
 	case TB_HITTEST:
 	    return TOOLBAR_HitTest (wndPtr, wParam, lParam);
 
-//	case TB_INDETERMINATE:
-//	    return TOOLBAR_Indeterminate (wndPtr, wParam, lParam);
+	case TB_INDETERMINATE:
+	    return TOOLBAR_Indeterminate (wndPtr, wParam, lParam);
 
-//	case TB_INSERTBUTTON:
-//	    return TOOLBAR_InsertButton (wndPtr, wParam, lParam);
+	case TB_INSERTBUTTON32A:
+	    return TOOLBAR_InsertButton32A (wndPtr, wParam, lParam);
 
+//	case TB_INSERTBUTTON32W:
 //	case TB_INSERTMARKHITTEST:		/* 4.71 */
 
 	case TB_ISBUTTONCHECKED:
@@ -1159,18 +1725,17 @@
 	    return TOOLBAR_IsButtonPressed (wndPtr, wParam, lParam);
 
 //	case TB_LOADIMAGES:			/* 4.70 */
-//	case TB_MAPACCELERATOR:			/* 4.71 */
-
+//	case TB_MAPACCELERATOR32A:		/* 4.71 */
+//	case TB_MAPACCELERATOR32W:		/* 4.71 */
 //	case TB_MARKBUTTON:			/* 4.71 */
-//	    return TOOLBAR_MarkButton (wndPtr, wParam, lParam);
-
 //	case TB_MOVEBUTTON:			/* 4.71 */
 
 	case TB_PRESSBUTTON:
 	    return TOOLBAR_PressButton (wndPtr, wParam, lParam);
 
 //	case TB_REPLACEBITMAP:
-//	case TB_SAVERESTORE:
+//	case TB_SAVERESTORE32A:
+//	case TB_SAVERESTORE32W:
 //	case TB_SETANCHORHIGHLIGHT:		/* 4.71 */
 
 	case TB_SETBITMAPSIZE:
@@ -1201,8 +1766,12 @@
 //	case TB_SETINSERTMARKCOLOR:		/* 4.71 */
 //	case TB_SETMAXTEXTROWS:			/* 4.70 */
 //	case TB_SETPADDING:			/* 4.71 */
-//	case TB_SETPARENT:
-//	case TB_SETROWS:
+
+	case TB_SETPARENT:
+	    return TOOLBAR_SetParent (wndPtr, wParam, lParam);
+
+	case TB_SETROWS:
+	    return TOOLBAR_SetRows (wndPtr, wParam, lParam);
 
 	case TB_SETSTATE:
 	    return TOOLBAR_SetState (wndPtr, wParam, lParam);
@@ -1210,7 +1779,9 @@
 	case TB_SETSTYLE:
 	    return TOOLBAR_SetStyle (wndPtr, wParam, lParam);
 
-//	case TB_SETTOOLTIPS:
+	case TB_SETTOOLTIPS:
+	    return TOOLBAR_SetToolTips (wndPtr, wParam, lParam);
+
 //	case TB_SETUNICODEFORMAT:
 
 	case WM_CREATE: