Release 970525

Tue May 20 19:20:23 1997  Pablo Saratxaga <srtxg@linux.chanae.stben.be>

	* [resources/sysres_Es.rc]
	Updated CHOOSE_FONT, CHOOSE_COLOR, EDITMENU for Spanish.

Mon May 19 22:06:04 1997  Michiel van Loon <mfvl@xs4all.nl>

	* [multimedia/mcistring.c]
	Corrected bug for device!element command.

	* [multimedia/mmaux.c]
	Replaced printf and fprintf calls by dprintf_mmaux.

	* [multimedia/audio.c]
	Corrected debugmessage in wodGetVolume.
	Include code for MCI_CUE command.

	* [multimedia/mmsystem.c]
	Added the MCIERR_SEQ error messages.

	* [if1632/mmsystem.spec] [multimedia/audio.c] [multimedia/mmsystem.c]
	Changed call structure of waveInOpen and waveOutOpen.

	* [multimedia/mmsystem.c] [multimedia/audio.c] [multimedia/midi.c]
	  [multimedia/mmaux.c] [multimedia/mcicda.c] [multimedia/mcianim.c]
	  [multimedia/mcistring.c] [include/mmsystem.h]
	Changed the deviceID scheme.

	* [include/queue.h] [include/win16drv.h] [msdos/dpmi.c]
	  [windows/user.c] [windows/driver.c] [graphic/wing.c]
	  [graphics/x11drv/bitmap.c] [misc/wsprintf.c] [misc/crtdll.c]
	Removed compiler warnings.

Mon May 19 01:32:24 1997  Alex Korobka <alex@trantor.pharm.sunysb.edu>

	* [controls/menu.c] [windows/win.c] [windows/graphics.c]
	Popup menu shade, new system menu implementation, 
	ModifyMenu() fixes, better check mark painting.

	* [windows/mdi.c]
	MDI client fix for Win32.

Sat May 17 12:02:11 1997  Albrecht Kleine  <kleine@ak.sax.de>

	* [objects/metafile.c]
	Added handling of META_DIBBITBLT, META_SETTEXTJUSTIFICATION
	plus bugfix in META_EXTTEXTOUT (start_of_text etc.)

Thu May 15 22:52:00 1997  Jimen Ching  <jching@flex.com>

	* [loader/ne_image.c]
	Make sure dgroup is valid by checking pModule->flags consistently.
diff --git a/ANNOUNCE b/ANNOUNCE
index 2b89c81..0ede2e6 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -1,13 +1,13 @@
-This is release 970509 of Wine, the MS Windows emulator.  This is still a
+This is release 970525 of Wine, the MS Windows emulator.  This is still a
 developer's only release.  There are many bugs and many unimplemented API
 features.  Most applications still do not work correctly.
 
 Patches should be submitted to "julliard@lrc.epfl.ch".  Please don't
 forget to include a ChangeLog entry.
 
-WHAT'S NEW with Wine-970509: (see ChangeLog for details)
-	- Better local heap implementation.
-	- Improvements to -managed mode.
+WHAT'S NEW with Wine-970525: (see ChangeLog for details)
+	- Many fixes to multimedia code.
+	- Better menus.
 	- Lots of bug fixes.
 
 See the README file in the distribution for installation instructions.
@@ -16,11 +16,10 @@
 the release is available at the ftp sites.  The sources will be available
 from the following locations:
 
-  ftp://sunsite.unc.edu/pub/Linux/ALPHA/wine/development/Wine-970509.tar.gz
-  ftp://tsx-11.mit.edu/pub/linux/ALPHA/Wine/development/Wine-970509.tar.gz
-  ftp://ftp.infomagic.com/pub/mirrors/linux/wine/development/Wine-970509.tar.gz
-  ftp://aris.com/pub/linux/ALPHA/Wine/development/Wine-970509.tar.gz
-  ftp://ftp.progsoc.uts.edu.au/pub/Wine/development/Wine-970509.tar.gz
+  ftp://sunsite.unc.edu/pub/Linux/ALPHA/wine/development/Wine-970525.tar.gz
+  ftp://tsx-11.mit.edu/pub/linux/ALPHA/Wine/development/Wine-970525.tar.gz
+  ftp://ftp.infomagic.com/pub/mirrors/linux/wine/development/Wine-970525.tar.gz
+  ftp://ftp.progsoc.uts.edu.au/pub/Wine/development/Wine-970525.tar.gz
 
 It should also be available from any site that mirrors tsx-11 or sunsite.
 
diff --git a/BUGS b/BUGS
index 79ef935..1252d8a 100644
--- a/BUGS
+++ b/BUGS
@@ -40,8 +40,6 @@
  * 32-bit Freecell segfaults when started from the Progman (looks like
    a problem with cards.dll).
 
- * Word 6.0 often segfaults when system menu is double-clicked. 
-
  * Edit controls are prone to show blank space when, in fact, there is a
    text there.
 
diff --git a/ChangeLog b/ChangeLog
index 45d2aef..ebe3a6e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,58 @@
 ----------------------------------------------------------------------
+Tue May 20 19:20:23 1997  Pablo Saratxaga <srtxg@linux.chanae.stben.be>
+
+	* [resources/sysres_Es.rc]
+	Updated CHOOSE_FONT, CHOOSE_COLOR, EDITMENU for Spanish.
+
+Mon May 19 22:06:04 1997  Michiel van Loon <mfvl@xs4all.nl>
+
+	* [multimedia/mcistring.c]
+	Corrected bug for device!element command.
+
+	* [multimedia/mmaux.c]
+	Replaced printf and fprintf calls by dprintf_mmaux.
+
+	* [multimedia/audio.c]
+	Corrected debugmessage in wodGetVolume.
+	Include code for MCI_CUE command.
+
+	* [multimedia/mmsystem.c]
+	Added the MCIERR_SEQ error messages.
+
+	* [if1632/mmsystem.spec] [multimedia/audio.c] [multimedia/mmsystem.c]
+	Changed call structure of waveInOpen and waveOutOpen.
+
+	* [multimedia/mmsystem.c] [multimedia/audio.c] [multimedia/midi.c]
+	  [multimedia/mmaux.c] [multimedia/mcicda.c] [multimedia/mcianim.c]
+	  [multimedia/mcistring.c] [include/mmsystem.h]
+	Changed the deviceID scheme.
+
+	* [include/queue.h] [include/win16drv.h] [msdos/dpmi.c]
+	  [windows/user.c] [windows/driver.c] [graphic/wing.c]
+	  [graphics/x11drv/bitmap.c] [misc/wsprintf.c] [misc/crtdll.c]
+	Removed compiler warnings.
+
+Mon May 19 01:32:24 1997  Alex Korobka <alex@trantor.pharm.sunysb.edu>
+
+	* [controls/menu.c] [windows/win.c] [windows/graphics.c]
+	Popup menu shade, new system menu implementation, 
+	ModifyMenu() fixes, better check mark painting.
+
+	* [windows/mdi.c]
+	MDI client fix for Win32.
+
+Sat May 17 12:02:11 1997  Albrecht Kleine  <kleine@ak.sax.de>
+
+	* [objects/metafile.c]
+	Added handling of META_DIBBITBLT, META_SETTEXTJUSTIFICATION
+	plus bugfix in META_EXTTEXTOUT (start_of_text etc.)
+
+Thu May 15 22:52:00 1997  Jimen Ching  <jching@flex.com>
+
+	* [loader/ne_image.c]
+	Make sure dgroup is valid by checking pModule->flags consistently.
+
+----------------------------------------------------------------------
 Tue May  6 19:12:20 1997  Alexandre Julliard  <julliard@lrc.epfl.ch>
 
 	* [loader/task.c] [loader/module.c]
diff --git a/Makefile.in b/Makefile.in
index afb9edd..039c741 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -122,7 +122,7 @@
 	$(INSTALL_DATA) libwine.a $(libdir)
 
 libwine.so.1.0: $(COMMONSUBDIRS) $(LIBSUBDIRS) dummy
-	$(CC) -shared -Wl,-soname,libwine.so.1 -o$@ $(COMMONOBJS) $(LIBOBJS) $(LDOPTIONS) $(X_LIBS) $(XPM_LIB) $(XLIB) $(LDLIBS)
+	$(CC) -shared -Wl,-soname,libwine.so -o$@ $(COMMONOBJS) $(LIBOBJS) $(LDOPTIONS) $(X_LIBS) $(XPM_LIB) $(XLIB) $(LDLIBS)
 
 install_libwine.so.1.0: dummy
 	$(INSTALL_DATA) libwine.so.1.0 $(libdir)
diff --git a/controls/button.c b/controls/button.c
index 72e2893..07cc5e1 100644
--- a/controls/button.c
+++ b/controls/button.c
@@ -413,7 +413,7 @@
         else if (infoPtr->state & BUTTON_3STATE) y += 2 * checkBoxHeight;
 
         GRAPH_DrawBitmap( hDC, hbitmapCheckBoxes, rbox.left, rbox.top + delta,
-                          x, y, checkBoxWidth, checkBoxHeight );
+                          x, y, checkBoxWidth, checkBoxHeight, FALSE );
         if( textlen && action != ODA_SELECT )
         {
             if (wndPtr->dwStyle & WS_DISABLED)
diff --git a/controls/desktop.c b/controls/desktop.c
index 2466ea7..6708fb7 100644
--- a/controls/desktop.c
+++ b/controls/desktop.c
@@ -108,7 +108,7 @@
 		    GRAPH_DrawBitmap( hdc, infoPtr->hbitmapWallPaper,
 				      x, y, 0, 0, 
 				      infoPtr->bitmapSize.cx,
-				      infoPtr->bitmapSize.cy );
+				      infoPtr->bitmapSize.cy, FALSE );
 	}
 	else
 	{
@@ -116,8 +116,9 @@
 	    y = (rect.top + rect.bottom - infoPtr->bitmapSize.cy) / 2;
 	    if (x < 0) x = 0;
 	    if (y < 0) y = 0;
-	    GRAPH_DrawBitmap( hdc, infoPtr->hbitmapWallPaper, x, y, 0, 0, 
-                              infoPtr->bitmapSize.cx, infoPtr->bitmapSize.cy );
+	    GRAPH_DrawBitmap( hdc, infoPtr->hbitmapWallPaper, 
+			      x, y, 0, 0, infoPtr->bitmapSize.cx, 
+			      infoPtr->bitmapSize.cy, FALSE );
 	}
     }
 
diff --git a/controls/listbox.c b/controls/listbox.c
index 8a7f1d9..48b181f 100644
--- a/controls/listbox.c
+++ b/controls/listbox.c
@@ -724,6 +724,7 @@
     item = descr->items + start + 1;
     if (HAS_STRINGS(descr))
     {
+        if (!str) return LB_ERR;
         if (exact)
         {
             for (i = start + 1; i < descr->nb_items; i++, item++)
@@ -1915,6 +1916,11 @@
                                   !descr->items[descr->focus_item].selected,
                                   (descr->style & LBS_NOTIFY) != 0 );
         }
+        else if (descr->selected_item == -1)
+        {
+            LISTBOX_SetSelection( wnd, descr, descr->focus_item, TRUE,
+                                  (descr->style & LBS_NOTIFY) != 0 );
+        }
         break;
     }
     if (caret >= 0)
diff --git a/controls/menu.c b/controls/menu.c
index f266e8f..4c7c82f 100644
--- a/controls/menu.c
+++ b/controls/menu.c
@@ -11,11 +11,14 @@
  * This is probably not the meaning this style has in MS-Windows.
  */
 
+#include <assert.h>
 #include <ctype.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include "windows.h"
+#include "bitmap.h"
+#include "gdi.h"
 #include "syscolor.h"
 #include "sysmetrics.h"
 #include "task.h"
@@ -32,6 +35,17 @@
 #include "stddebug.h"
 #include "debug.h"
 
+/* internal popup menu window messages */
+
+#define MM_SETMENUHANDLE	(WM_USER + 0)
+#define MM_GETMENUHANDLE	(WM_USER + 1)
+
+typedef struct
+{
+  HBITMAP32	hCheckBit;
+  HBITMAP32	hUnCheckBit;
+} CBITMAPS, *PCBITMAPS;
+
 /* Menu item structure */
 typedef struct
 {
@@ -39,8 +53,7 @@
     UINT32      item_id;       /* Item or popup id */
     RECT32      rect;          /* Item area (relative to menu window) */
     UINT32      xTab;          /* X position of text after Tab */
-    HBITMAP32   hCheckBit;     /* Bitmap for checked item */
-    HBITMAP32   hUnCheckBit;   /* Bitmap for unchecked item */
+    PCBITMAPS	pCB;	       /* checkmark bitmaps */
     LPSTR       text;          /* Item text or bitmap handle */
 } MENUITEM;
 
@@ -58,17 +71,34 @@
     UINT32      FocusedItem;  /* Currently focused item */
 } POPUPMENU, *LPPOPUPMENU;
 
+/* internal flags for menu tracking */
+
+#define TF_ENDMENU              0x0001
+#define TF_SUSPENDPOPUP         0x0002
+#define TF_SKIPREMOVE		0x0004
+
+typedef struct
+{
+    UINT32	trackFlags;
+    HMENU32	hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
+    HMENU32	hTopMenu;     /* initial menu */
+    HWND32	hOwnerWnd;    /* where notifications are sent */
+    POINT32	pt;
+} MTRACKER;
+
 #define MENU_MAGIC   0x554d  /* 'MU' */
 
 #define ITEM_PREV		-1
 #define ITEM_NEXT		 1
 
-  /* Dimension of the menu bitmaps */
-static WORD check_bitmap_width = 0, check_bitmap_height = 0;
-static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
+  /* Internal MENU_TrackMenu() flags */
+#define TPM_INTERNAL		0xF0000000
+#define TPM_ENTERIDLEEX	 	0x80000000		/* set owner window for WM_ENTERIDLE */
+#define TPM_BUTTONDOWN		0x40000000		/* menu was clicked before tracking */
 
-  /* Flag set by EndMenu() to force an exit from menu tracking */
-static BOOL32 fEndMenuCalled = FALSE;
+  /* popup menu shade thickness */
+#define POPUP_XSHADE		4
+#define POPUP_YSHADE		4
 
   /* Space between 2 menu bar items */
 #define MENU_BAR_ITEMS_SPACE  16
@@ -79,46 +109,93 @@
   /* Height of a separator item */
 #define SEPARATOR_HEIGHT      5
 
-  /* Values for menu->FocusedItem */
-  /* (other values give the position of the focused item) */
+  /* (other menu->FocusedItem values give the position of the focused item) */
 #define NO_SELECTED_ITEM  0xffff
-#define SYSMENU_SELECTED  0xfffe  /* Only valid on menu-bars */
 
 #define IS_STRING_ITEM(flags) \
     (!((flags) & (MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)))
+#define IS_SYSTEM_MENU(menu)  \
+	(!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
+#define IS_SYSTEM_POPUP(menu) \
+	((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
+
+  /* Dimension of the menu bitmaps */
+static WORD check_bitmap_width = 0, check_bitmap_height = 0;
+static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
 
 static HBITMAP32 hStdCheck = 0;
 static HBITMAP32 hStdMnArrow = 0;
-static HMENU32 MENU_DefSysMenu = 0;  /* Default system menu */
+static HBRUSH32 hShadeBrush = 0;
+static HMENU32 MENU_DefSysPopup = 0;  /* Default system menu popup */
 
+/* Use global popup window because there's no way 2 menus can
+ * be tracked at the same time.  */ 
 
-/* we _can_ use global popup window because there's no way 2 menues can
- * be tracked at the same time.
- */ 
-
-static WND* pTopPWnd   = 0;
+static WND* pTopPopupWnd   = 0;
 static UINT32 uSubPWndLevel = 0;
 
+  /* Flag set by EndMenu() to force an exit from menu tracking */
+static BOOL32 fEndMenu = FALSE;
+
+
+/***********************************************************************
+ *           MENU_CopySysPopup
+ *
+ * Return the default system menu.
+ */
+static HMENU32 MENU_CopySysPopup(void)
+{
+    HMENU32 hMenu = LoadMenuIndirect32A(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU));
+
+    if( hMenu )
+    {
+        POPUPMENU* menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
+        menu->wFlags |= MF_SYSMENU | MF_POPUP;
+	return hMenu;
+    }
+    else fprintf( stderr, "Unable to load default system menu\n" );
+    return FALSE;
+}
+
 
 /**********************************************************************
- *           MENU_CopySysMenu
+ *           MENU_GetSysMenu
  *
- * Load a copy of the system menu.
+ * Create a copy of the system menu. System menu in Windows is
+ * a special menu-bar with the single entry - system menu popup.
+ * This popup is presented to the outside world as a "system menu". 
+ * However, the real system menu handle is sometimes seen in the 
+ * WM_MENUSELECT paramemters (and Word 6 likes it this way).
  */
-static HMENU32 MENU_CopySysMenu(void)
+HMENU32 MENU_GetSysMenu( HWND32 hWnd, HMENU32 hPopupMenu )
 {
     HMENU32 hMenu;
-    POPUPMENU *menu;
 
-    if (!(hMenu = LoadMenuIndirect32A( SYSRES_GetResPtr(SYSRES_MENU_SYSMENU))))
+    if ((hMenu = CreateMenu32()))
     {
-	dprintf_menu(stddeb,"No SYSMENU\n");
-	return 0;
+	POPUPMENU *menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
+	menu->wFlags = MF_SYSMENU;
+	menu->hWnd = hWnd;
+
+	if (hPopupMenu == (HMENU32)(-1))
+	    hPopupMenu = MENU_CopySysPopup();
+	else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup; 
+
+	if (hPopupMenu)
+	{
+	    InsertMenu32A( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION, hPopupMenu, NULL );
+
+	    menu->items[0].item_flags = MF_SYSMENU | MF_POPUP;
+	    menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hPopupMenu);
+	    menu->wFlags |= MF_SYSMENU;
+
+	    dprintf_menu(stddeb,"GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu );
+	    return hMenu;
+	}
+	DestroyMenu32( hMenu );
     }
-    menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
-    menu->wFlags |= MF_SYSMENU | MF_POPUP;
-    dprintf_menu(stddeb,"CopySysMenu hMenu=%04x !\n", hMenu);
-    return hMenu;
+    fprintf(stderr, "failed to load system menu!\n");
+    return 0;
 }
 
 
@@ -129,79 +206,40 @@
  */
 BOOL32 MENU_Init()
 {
-    BITMAP32 bm;
+    /* Load menu bitmaps */
 
-      /* Load bitmaps */
-
-    if (!(hStdCheck = LoadBitmap32A( 0, (LPSTR)MAKEINTRESOURCE(OBM_CHECK) )))
-	return FALSE;
-    GetObject32A( hStdCheck, sizeof(bm), &bm );
-    check_bitmap_width = bm.bmWidth;
-    check_bitmap_height = bm.bmHeight;
-    if (!(hStdMnArrow = LoadBitmap32A(0,(LPSTR)MAKEINTRESOURCE(OBM_MNARROW))))
-	return FALSE;
-    GetObject32A( hStdMnArrow, sizeof(bm), &bm );
-    arrow_bitmap_width = bm.bmWidth;
-    arrow_bitmap_height = bm.bmHeight;
-
-    if (!(MENU_DefSysMenu = MENU_CopySysMenu()))
+    if ((hStdCheck = LoadBitmap32A( 0, (LPSTR)MAKEINTRESOURCE(OBM_CHECK) )))
     {
-        fprintf( stderr, "Unable to create default system menu\n" );
-        return FALSE;
+	BITMAP32 bm;
+
+	GetObject32A( hStdCheck, sizeof(bm), &bm );
+	check_bitmap_width = bm.bmWidth;
+	check_bitmap_height = bm.bmHeight;
+
+	if ((hStdMnArrow = LoadBitmap32A(0,(LPSTR)MAKEINTRESOURCE(OBM_MNARROW))))
+	{
+	    HBITMAP32 hBitmap;
+	    static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
+						    0x55, 0, 0xAA, 0,
+						    0x55, 0, 0xAA, 0,
+						    0x55, 0, 0xAA, 0 };
+	    GetObject32A( hStdMnArrow, sizeof(bm), &bm );
+	    arrow_bitmap_width = bm.bmWidth;
+	    arrow_bitmap_height = bm.bmHeight;
+
+	    if((hBitmap = CreateBitmap32( 8, 8, 1, 1, shade_bits)))
+	    {
+		if((hShadeBrush = CreatePatternBrush32( hBitmap )))
+		{
+		    DeleteObject32( hBitmap );
+		    if((MENU_DefSysPopup = MENU_CopySysPopup())) return TRUE;
+		}
+	    }
+	}
     }
-    return TRUE;
+    return FALSE;	/* failure */
 }
 
-
-/***********************************************************************
- *           MENU_GetDefSysMenu
- *
- * Return the default system menu.
- */
-HMENU32 MENU_GetDefSysMenu(void)
-{
-    return MENU_DefSysMenu;
-}
-
-
-/***********************************************************************
- *           MENU_HasSysMenu
- *
- * Check whether the window owning the menu bar has a system menu.
- */
-static BOOL32 MENU_HasSysMenu( POPUPMENU *menu )
-{
-    WND *wndPtr;
-
-    if (menu->wFlags & MF_POPUP) return FALSE;
-    if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return FALSE;
-    return (wndPtr->dwStyle & WS_SYSMENU) != 0;
-}
-
-
-/***********************************************************************
- *           MENU_IsInSysMenu
- *
- * Check whether the point (in screen coords) is in the system menu
- * of the window owning the given menu.
- */
-static BOOL32 MENU_IsInSysMenu( POPUPMENU *menu, POINT32 pt )
-{
-    WND *wndPtr;
-
-    if (menu->wFlags & MF_POPUP) return FALSE;
-    if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return FALSE;
-    if (!(wndPtr->dwStyle & WS_SYSMENU)) return FALSE;
-    if ((pt.x < wndPtr->rectClient.left) ||
-	(pt.x >= wndPtr->rectClient.left+SYSMETRICS_CXSIZE+SYSMETRICS_CXBORDER))
-	return FALSE;
-    if ((pt.y >= wndPtr->rectClient.top - menu->Height) ||
-	(pt.y < wndPtr->rectClient.top - menu->Height -
-	              SYSMETRICS_CYSIZE - SYSMETRICS_CYBORDER)) return FALSE;
-    return TRUE;
-}
-
-
 /***********************************************************************
  *           MENU_InitSysMenuPopup
  *
@@ -268,27 +306,43 @@
     return NULL;
 }
 
+/***********************************************************************
+ *           MENU_FreeItemData
+ */
+static void MENU_FreeItemData( MENUITEM* item )
+{
+    /* delete text */
+
+    if (IS_STRING_ITEM(item->item_flags) && item->text)
+        HeapFree( SystemHeap, 0, item->text );
+
+    /* delete checkmark stuff */
+
+    if (item->pCB) HeapFree( SystemHeap, 0, item->pCB );
+}
 
 /***********************************************************************
  *           MENU_FindItemByCoords
  *
- * Find the item at the specified coordinates (screen coords).
+ * Find the item at the specified coordinates (screen coords). Does 
+ * not work for child windows and therefore should not be called for 
+ * an arbitrary system menu.
  */
-static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu, INT32 x, INT32 y,
-                                        UINT32 *pos )
+static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu, 
+					POINT32 pt, UINT32 *pos )
 {
     MENUITEM *item;
     WND *wndPtr;
     UINT32 i;
 
     if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return NULL;
-    x -= wndPtr->rectWindow.left;
-    y -= wndPtr->rectWindow.top;
+    pt.x -= wndPtr->rectWindow.left;
+    pt.y -= wndPtr->rectWindow.top;
     item = menu->items;
     for (i = 0; i < menu->nItems; i++, item++)
     {
-	if ((x >= item->rect.left) && (x < item->rect.right) &&
-	    (y >= item->rect.top) && (y < item->rect.bottom))
+	if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
+	    (pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
 	{
 	    if (pos) *pos = i;
 	    return item;
@@ -309,7 +363,11 @@
 {
     dprintf_menu(stddeb,"\tlooking for '%c' in [%04x]\n", (char)key, (UINT16)hmenu );
 
-    if (!IsMenu32( hmenu )) hmenu = WIN_FindWndPtr(hwndOwner)->hSysMenu;
+    if (!IsMenu32( hmenu )) 
+    {
+	WND* w = WIN_FindWndPtr(hwndOwner);
+	hmenu = GetSubMenu32(w->hSysMenu, 0);
+    }
 
     if (hmenu)
     {
@@ -437,12 +495,13 @@
     lppop->Width = lppop->Height = 0;
     if (lppop->nItems == 0) return;
     hdc = GetDC32( 0 );
-    maxX = start = 0;
+    start = 0;
+    maxX = SYSMETRICS_CXBORDER;
     while (start < lppop->nItems)
     {
 	lpitem = &lppop->items[start];
 	orgX = maxX;
-	orgY = 0;
+	orgY = SYSMETRICS_CYBORDER;
 	maxTab = maxTabWidth = 0;
 
 	  /* Parse items until column break or end of menu */
@@ -480,6 +539,10 @@
 /***********************************************************************
  *           MENU_MenuBarCalcSize
  *
+ * FIXME: Word 6 implements it's own MDI and it's 'close window' bitmap
+ * height is off by 1 pixel which causes lengthy window relocations when
+ * active document window is maximized/restored.
+ *
  * Calculate the size of the menu bar.
  */
 static void MENU_MenuBarCalcSize( HDC32 hdc, LPRECT32 lprect,
@@ -544,7 +607,6 @@
     }
 }
 
-
 /***********************************************************************
  *           MENU_DrawMenuItem
  *
@@ -555,6 +617,13 @@
 {
     RECT32 rect;
 
+    if (lpitem->item_flags & MF_SYSMENU)
+    {
+	if( !IsIconic32(hwnd) ) NC_DrawSysButton( hwnd, hdc, 
+				lpitem->item_flags & (MF_HILITE | MF_MOUSESELECT));
+	return;
+    }
+
     if (lpitem->item_flags & MF_OWNERDRAW)
     {
         DRAWITEMSTRUCT32 dis;
@@ -622,21 +691,23 @@
 
     if (!menuBar)
     {
-	  /* Draw the check mark */
+	INT32	y = rect.top + rect.bottom;
+
+	  /* Draw the check mark
+	   *
+	   * Custom checkmark bitmaps are monochrome but not always 1bpp. 
+	   * In this case we want GRAPH_DrawBitmap() to copy a plane which 
+	   * is 1 for a white pixel and 0 for a black one. 
+	   */
 
 	if (lpitem->item_flags & MF_CHECKED)
-	{
-	    GRAPH_DrawBitmap(hdc, lpitem->hCheckBit ? lpitem->hCheckBit :
-			     hStdCheck, rect.left,
-			     (rect.top+rect.bottom-check_bitmap_height) / 2,
-			     0, 0, check_bitmap_width, check_bitmap_height );
-	}
-	else if (lpitem->hUnCheckBit != 0)  /* Not checked */
-	{
-	    GRAPH_DrawBitmap(hdc, lpitem->hUnCheckBit, rect.left,
-			     (rect.top+rect.bottom-check_bitmap_height) / 2,
-			     0, 0, check_bitmap_width, check_bitmap_height );
-	}
+            GRAPH_DrawBitmap( hdc, lpitem->pCB ? lpitem->pCB->hCheckBit
+			      : hStdCheck, rect.left, (y - check_bitmap_height) / 2, 
+			      0, 0, check_bitmap_width, check_bitmap_height, TRUE );
+	else if (lpitem->pCB)
+	    GRAPH_DrawBitmap( hdc, lpitem->pCB->hUnCheckBit, rect.left, 
+			      (y - check_bitmap_height) / 2, 0, 0,
+			      check_bitmap_width, check_bitmap_height, TRUE );
 
 	  /* Draw the popup-menu arrow */
 
@@ -644,8 +715,8 @@
 	{
 	    GRAPH_DrawBitmap( hdc, hStdMnArrow,
 			      rect.right-arrow_bitmap_width-1,
-			      (rect.top+rect.bottom-arrow_bitmap_height) / 2,
-                              0, 0, arrow_bitmap_width, arrow_bitmap_height );
+			      (y - arrow_bitmap_height) / 2, 0, 0, 
+			      arrow_bitmap_width, arrow_bitmap_height, FALSE );
 	}
 
 	rect.left += check_bitmap_width;
@@ -658,7 +729,7 @@
     {
 	GRAPH_DrawBitmap( hdc, (HBITMAP32)lpitem->text,
                           rect.left, rect.top, 0, 0,
-                          rect.right-rect.left, rect.bottom-rect.top );
+                          rect.right-rect.left, rect.bottom-rect.top, FALSE );
 	return;
     }
     /* No bitmap - process text if present */
@@ -704,17 +775,54 @@
  */
 static void MENU_DrawPopupMenu( HWND32 hwnd, HDC32 hdc, HMENU32 hmenu )
 {
-    POPUPMENU *menu;
-    MENUITEM *item;
+    HBRUSH32 hPrevBrush = 0;
     RECT32 rect;
-    UINT32 i;
 
     GetClientRect32( hwnd, &rect );
-    FillRect32( hdc, &rect, sysColorObjects.hbrushMenu );
-    menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
-    if (!menu || !menu->nItems) return;
-    for (i = menu->nItems, item = menu->items; i > 0; i--, item++)
-	MENU_DrawMenuItem( hwnd, hdc, item, menu->Height, FALSE );
+    rect.bottom -= POPUP_YSHADE * SYSMETRICS_CYBORDER;
+    rect.right -= POPUP_XSHADE * SYSMETRICS_CXBORDER;
+
+    if((hPrevBrush = SelectObject32( hdc, sysColorObjects.hbrushMenu )))
+    {
+	HPEN32 hPrevPen;
+
+	Rectangle32( hdc, rect.left, rect.top, rect.right, rect.bottom );
+	hPrevPen = SelectObject32( hdc, GetStockObject32( NULL_PEN ) );
+	if( hPrevPen )
+	{
+	    INT32 ropPrev, i;
+	    POPUPMENU *menu;
+
+	    /* draw 3-d shade */
+
+	    SelectObject32( hdc, hShadeBrush );
+	    SetBkMode32( hdc, TRANSPARENT );
+	    ropPrev = SetROP232( hdc, R2_MASKPEN );
+
+	    i = rect.right;		/* why SetBrushOrg() doesn't? */
+	    PatBlt32( hdc, i & 0xfffffffe, rect.top + POPUP_YSHADE*SYSMETRICS_CYBORDER, 
+		      i%2 + POPUP_XSHADE*SYSMETRICS_CXBORDER, rect.bottom - rect.top, 0x00a000c9 );
+	    i = rect.bottom;
+	    PatBlt32( hdc, rect.left + POPUP_XSHADE*SYSMETRICS_CXBORDER, i & 0xfffffffe, 
+		      rect.right - rect.left, i%2 + POPUP_YSHADE*SYSMETRICS_CYBORDER, 0x00a000c9 );
+	    SelectObject32( hdc, hPrevPen );
+	    SelectObject32( hdc, hPrevBrush );
+	    SetROP232( hdc, ropPrev );
+
+	    /* draw menu items */
+
+	    menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
+	    if (menu && menu->nItems)
+	    {
+		MENUITEM *item;
+		UINT32 u;
+
+		for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
+		    MENU_DrawMenuItem( hwnd, hdc, item, menu->Height, FALSE );
+
+	    }
+	} else SelectObject32( hdc, hPrevBrush );
+    }
 }
 
 
@@ -753,34 +861,60 @@
 
 
 /***********************************************************************
- *	     MENU_SwitchTPWndTo
+ *	     MENU_PatchResidentPopup
  */
-BOOL32 MENU_SwitchTPWndTo( HTASK16 hTask )
+BOOL32 MENU_PatchResidentPopup( HQUEUE16 checkQueue, WND* wndOwner )
 {
-  /* This is supposed to be called when popup is hidden. 
-   * AppExit() calls with hTask == 0, so we get the next to current.
-   */
+   /* checkQueue tells us whether we have to disconnect top
+    * popup from the wndOwner or (if the latter is NULL) from 
+    * the checkQueue. If checkQueue is 0 then we need to set 
+    * popup owner to the wndOwner.
+    *
+    * This is supposed to be called when top popup is hidden. */
 
-  TDB* task;
+    if( pTopPopupWnd )
+    {
+	HTASK16 hTask = 0;
 
-  if( !pTopPWnd ) return 0;
+	dprintf_menu(stddeb,"patching resident popup: %04x, %08x\n", 
+				   checkQueue, (unsigned) wndOwner);
+	if( wndOwner )
+	{
+	    if( pTopPopupWnd->owner == wndOwner )
+	    {
+		if( checkQueue ) pTopPopupWnd->owner = NULL;
+		return TRUE;
+	    }
+	
+	    /* switch to the new owner */
 
-  if( !hTask )
-  {
-    task = (TDB*)GlobalLock16( (hTask = GetCurrentTask()) );
-    if( task && task->hQueue == pTopPWnd->hmemTaskQ )
-	hTask = TASK_GetNextTask(hTask); 
-    else return 0;
-  }
+	    if( wndOwner->hmemTaskQ == pTopPopupWnd->hmemTaskQ ) 
+		return TRUE;
+	    hTask = QUEUE_GetQueueTask( wndOwner->hmemTaskQ );
+	} 
+	else if( pTopPopupWnd->hmemTaskQ == checkQueue )
+	{
+	    /* switch to the different task */
 
-  task = (TDB*)GlobalLock16(hTask);
-  if( !task ) return 0;
+	    hTask = QUEUE_GetQueueTask( pTopPopupWnd->hmemTaskQ );
+	    hTask = TASK_GetNextTask( hTask );  
+	}
 
-  /* if this task got as far as menu tracking it must have a queue */
+	if( hTask )
+	{
+	    TDB* task = (TDB*)GlobalLock16( hTask );
 
-  pTopPWnd->hInstance = task->hInstance;
-  pTopPWnd->hmemTaskQ = task->hQueue;
-  return 1;
+	    pTopPopupWnd->owner = wndOwner;
+	    if( task )
+	    {
+		pTopPopupWnd->hInstance = task->hInstance;
+		pTopPopupWnd->hmemTaskQ = task->hQueue;
+		return TRUE;
+	    } 
+	    else dprintf_menu(stddeb,"failed to patch resident popup.\n");
+	} 
+    }
+    return FALSE;
 }
 
 /***********************************************************************
@@ -792,9 +926,7 @@
                               INT32 x, INT32 y, INT32 xanchor, INT32 yanchor )
 {
     POPUPMENU 	*menu;
-    WND 	*wndPtr = NULL;
-    BOOL32	 skip_init = 0;
-    UINT32	 width, height;
+    WND 	*wndOwner = NULL;
 
     if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
     if (menu->FocusedItem != NO_SELECTED_ITEM)
@@ -802,82 +934,88 @@
 	menu->items[menu->FocusedItem].item_flags &= ~(MF_HILITE|MF_MOUSESELECT);
 	menu->FocusedItem = NO_SELECTED_ITEM;
     }
+
     SendMessage16( hwndOwner, WM_INITMENUPOPUP, (WPARAM16)hmenu,
                    MAKELONG( id, (menu->wFlags & MF_SYSMENU) ? 1 : 0 ));
-    MENU_PopupMenuCalcSize( menu, hwndOwner );
 
-    /* adjust popup menu pos so that it fits within the desktop */
-
-    width = menu->Width + 2*SYSMETRICS_CXBORDER;
-    height = menu->Height + 2*SYSMETRICS_CYBORDER; 
-
-    if( x + width > SYSMETRICS_CXSCREEN )
+    if( (wndOwner = WIN_FindWndPtr( hwndOwner )) )
     {
-	if( xanchor )
-            x -= width - xanchor;
-        if( x + width > SYSMETRICS_CXSCREEN)
-	    x = SYSMETRICS_CXSCREEN - width;
-    }
-    if( x < 0 )
-         x = 0;
+	UINT32	width, height;
 
-    if( y + height > SYSMETRICS_CYSCREEN )
-    { 
-	if( yanchor )
-	    y -= height + yanchor;
+	MENU_PopupMenuCalcSize( menu, hwndOwner );
+
+	/* adjust popup menu pos so that it fits within the desktop */
+
+	width = menu->Width + SYSMETRICS_CXBORDER;
+	height = menu->Height + SYSMETRICS_CYBORDER; 
+
+	if( x + width > SYSMETRICS_CXSCREEN )
+	{
+	    if( xanchor )
+            	x -= width - xanchor;
+            if( x + width > SYSMETRICS_CXSCREEN)
+	    	x = SYSMETRICS_CXSCREEN - width;
+	}
+	if( x < 0 ) x = 0;
+
 	if( y + height > SYSMETRICS_CYSCREEN )
-	    y = SYSMETRICS_CYSCREEN - height;
-    }
-    if( y < 0 )
-	y = 0;
+	{ 
+	    if( yanchor )
+	    	y -= height + yanchor;
+	    if( y + height > SYSMETRICS_CYSCREEN )
+	    	y = SYSMETRICS_CYSCREEN - height;
+	}
+	if( y < 0 ) y = 0;
 
-    wndPtr = WIN_FindWndPtr( hwndOwner );
-    if (!wndPtr) return FALSE;
+	width += POPUP_XSHADE * SYSMETRICS_CXBORDER;	/* add space for shading */
+	height += POPUP_YSHADE * SYSMETRICS_CYBORDER;
 
-    if (!pTopPWnd)
-    {
-	pTopPWnd = WIN_FindWndPtr(CreateWindow32A( POPUPMENU_CLASS_ATOM, NULL,
-                                          WS_POPUP | WS_BORDER, x, y,
-                                          width, height,
-                                          hwndOwner, 0, wndPtr->hInstance,
-                                          (LPVOID)hmenu ));
-	if (!pTopPWnd) return FALSE;
-	skip_init = TRUE;
-    }
+	/* NOTE: In Windows, top menu popup is not owned. */
+	if (!pTopPopupWnd)	/* create top level popup menu window */
+	{
+	    assert( uSubPWndLevel == 0 );
 
-    if( uSubPWndLevel )
-    {
-	/* create new window for the submenu */
-	HWND32 hWnd = CreateWindow32A( POPUPMENU_CLASS_ATOM, NULL,
-                                      WS_POPUP | WS_BORDER, x, y,
-                                      width, height,
-                                      menu->hWnd, 0, wndPtr->hInstance,
-                                      (LPVOID)hmenu );
-	if( !hWnd ) return FALSE;
-	menu->hWnd = hWnd;
-    }
-    else 
-    {
-	if( !skip_init )
-	  {
-            MENU_SwitchTPWndTo(GetCurrentTask());
-	    SendMessage16( pTopPWnd->hwndSelf, WM_USER, (WPARAM16)hmenu, 0L);
-	  }
-	menu->hWnd = pTopPWnd->hwndSelf;
-    }
+	    pTopPopupWnd = WIN_FindWndPtr(CreateWindow32A( POPUPMENU_CLASS_ATOM, NULL,
+					  WS_POPUP, x, y, width, height,
+					  hwndOwner, 0, wndOwner->hInstance,
+					  (LPVOID)hmenu ));
+	    if (!pTopPopupWnd) return FALSE;
+	    menu->hWnd = pTopPopupWnd->hwndSelf;
+	} 
+	else
+	    if( uSubPWndLevel )
+	    {
+		/* create a new window for the submenu */
 
-    uSubPWndLevel++;
+		menu->hWnd = CreateWindow32A( POPUPMENU_CLASS_ATOM, NULL,
+					  WS_POPUP, x, y, width, height,
+					  menu->hWnd, 0, wndOwner->hInstance,
+					  (LPVOID)hmenu );
+		if( !menu->hWnd ) return FALSE;
+	    }
+	    else /* top level popup menu window already exists */
+	    {
+		menu->hWnd = pTopPopupWnd->hwndSelf;
 
-    wndPtr = WIN_FindWndPtr( menu->hWnd );
+		MENU_PatchResidentPopup( 0, wndOwner );
+		SendMessage16( pTopPopupWnd->hwndSelf, MM_SETMENUHANDLE, (WPARAM16)hmenu, 0L);	
 
-    SetWindowPos32(menu->hWnd, 0, x, y, width, height,
-		  		      SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
+		/* adjust its size */
+
+	        SetWindowPos32( menu->hWnd, 0, x, y, width, height,
+				SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
+	    }
+
+	uSubPWndLevel++;	/* menu level counter */
+
       /* Display the window */
 
-    SetWindowPos32( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
-		    SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
-    UpdateWindow32( menu->hWnd );
-    return TRUE;
+	SetWindowPos32( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
+			SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
+	UpdateWindow32( menu->hWnd );
+	return TRUE;
+    }
+    return FALSE;
 }
 
 
@@ -892,10 +1030,11 @@
 
     lppop = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
     if (!lppop->nItems) return;
+
     if ((wIndex != NO_SELECTED_ITEM) && 
-	(wIndex != SYSMENU_SELECTED) &&
 	(lppop->items[wIndex].item_flags & MF_SEPARATOR))
 	wIndex = NO_SELECTED_ITEM;
+
     if (lppop->FocusedItem == wIndex) return;
     if (lppop->wFlags & MF_POPUP) hdc = GetDC32( lppop->hWnd );
     else hdc = GetDCEx32( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
@@ -903,104 +1042,83 @@
       /* Clear previous highlighted item */
     if (lppop->FocusedItem != NO_SELECTED_ITEM) 
     {
-	if (lppop->FocusedItem == SYSMENU_SELECTED)
-	    NC_DrawSysButton( lppop->hWnd, hdc, FALSE );
-	else
-	{
-	    lppop->items[lppop->FocusedItem].item_flags &=~(MF_HILITE|MF_MOUSESELECT);
-	    MENU_DrawMenuItem(lppop->hWnd,hdc,&lppop->items[lppop->FocusedItem],
-                              lppop->Height, !(lppop->wFlags & MF_POPUP) );
-	}
+	lppop->items[lppop->FocusedItem].item_flags &=~(MF_HILITE|MF_MOUSESELECT);
+	MENU_DrawMenuItem(lppop->hWnd,hdc,&lppop->items[lppop->FocusedItem],
+                          lppop->Height, !(lppop->wFlags & MF_POPUP) );
     }
 
       /* Highlight new item (if any) */
     lppop->FocusedItem = wIndex;
     if (lppop->FocusedItem != NO_SELECTED_ITEM) 
     {
-	if (lppop->FocusedItem == SYSMENU_SELECTED)
-        {
-	    NC_DrawSysButton( lppop->hWnd, hdc, TRUE );
-            if (sendMenuSelect)
-                SendMessage16( hwndOwner, WM_MENUSELECT,
-                             WIN_FindWndPtr(lppop->hWnd)->hSysMenu,
-                             MAKELONG(lppop->wFlags | MF_MOUSESELECT, hmenu));
-        }
-	else
-	{
-	    lppop->items[lppop->FocusedItem].item_flags |= MF_HILITE;
-	    MENU_DrawMenuItem( lppop->hWnd, hdc, &lppop->items[lppop->FocusedItem],
-                               lppop->Height, !(lppop->wFlags & MF_POPUP) );
-            if (sendMenuSelect)
-	        SendMessage16( hwndOwner, WM_MENUSELECT,
-                             lppop->items[lppop->FocusedItem].item_id,
-                             MAKELONG( lppop->items[lppop->FocusedItem].item_flags | MF_MOUSESELECT, hmenu));
-	}
+	lppop->items[lppop->FocusedItem].item_flags |= MF_HILITE;
+	MENU_DrawMenuItem( lppop->hWnd, hdc, &lppop->items[lppop->FocusedItem],
+                           lppop->Height, !(lppop->wFlags & MF_POPUP) );
+        if (sendMenuSelect)
+	    SendMessage16( hwndOwner, WM_MENUSELECT,
+                           lppop->items[lppop->FocusedItem].item_id,
+                           MAKELONG( lppop->items[lppop->FocusedItem].item_flags | MF_MOUSESELECT, hmenu));
     }
     else if (sendMenuSelect)
         SendMessage16( hwndOwner, WM_MENUSELECT, hmenu,
-                       MAKELONG( lppop->wFlags | MF_MOUSESELECT, hmenu ) );
+                       MAKELONG( lppop->wFlags | MF_MOUSESELECT, hmenu ) ); 
 
     ReleaseDC32( lppop->hWnd, hdc );
 }
 
 
 /***********************************************************************
- *           MENU_SelectItemRel
+ *           MENU_MoveSelection
  *
+ * Moves currently selected item according to the offset parameter.
+ * If there is no selection then it should select the last item if
+ * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
  */
-static void MENU_SelectItemRel( HWND32 hwndOwner, HMENU32 hmenu, INT32 offset )
+static void MENU_MoveSelection( HWND32 hwndOwner, HMENU32 hmenu, INT32 offset )
 {
-    INT32 i, min = 0;
+    INT32 i;
     POPUPMENU *menu;
 
     menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
     if (!menu->items) return;
-    if ((menu->FocusedItem != NO_SELECTED_ITEM) &&
-	(menu->FocusedItem != SYSMENU_SELECTED))
+
+    if ( menu->FocusedItem != NO_SELECTED_ITEM )
     {
+	if( menu->nItems == 1 ) return; else
 	for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems 
 					    ; i += offset)
-	{
 	    if (!(menu->items[i].item_flags & MF_SEPARATOR))
 	    {
 		MENU_SelectItem( hwndOwner, hmenu, i, TRUE );
 		return;
 	    }
-	}
-
-	if (MENU_HasSysMenu( menu ))
-	{
-	    MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED, TRUE );
-	    return;
-	}
     }
 
-    if( offset > 0 ) { i = 0; min = -1; }
-    else i = menu->nItems - 1;
-     
-    for ( ; i > min && i < menu->nItems ; i += offset)
-    {
+    for ( i = (offset > 0) ? 0 : menu->nItems - 1; 
+		  i >= 0 && i < menu->nItems ; i += offset)
 	if (!(menu->items[i].item_flags & MF_SEPARATOR))
 	{
 	    MENU_SelectItem( hwndOwner, hmenu, i, TRUE );
 	    return;
 	}
-    }
-    if (MENU_HasSysMenu( menu ))
-        MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED, TRUE );
 }
 
 
 /**********************************************************************
  *         MENU_SetItemData
  *
- * Set an item flags, id and text ptr.
+ * Set an item flags, id and text ptr. Called by InsertMenu() and
+ * ModifyMenu().
  */
 static BOOL32 MENU_SetItemData( MENUITEM *item, UINT32 flags, UINT32 id,
                                 LPCSTR str )
 {
     LPSTR prevText = IS_STRING_ITEM(item->item_flags) ? item->text : NULL;
 
+    dprintf_menu(stddeb,"SetItemData: %04x [%08x] '%s'  -> %04x [%08x] '%s'\n",
+		 item->item_flags, item->item_id, item->text ? item->text : "",
+		 flags, id, str ? str : "" );
+
     if (IS_STRING_ITEM(flags))
     {
         if (!str)
@@ -1025,8 +1143,20 @@
     else if (flags & MF_OWNERDRAW) item->text = (LPSTR)str;
     else item->text = NULL;
 
+    if (item->item_flags & MF_POPUP && item->item_id != id )
+	DestroyMenu32( (HMENU32)item->item_id );   /* ModifyMenu() spec */
+
+    if (flags & MF_POPUP)
+    {
+	POPUPMENU*	menu = (POPUPMENU *)USER_HEAP_LIN_ADDR((UINT16)id);
+	if( menu && menu->wMagic == MENU_MAGIC) menu->wFlags |= MF_POPUP;
+	else
+	    return (item->item_id = item->item_flags = FALSE);
+    }
+
     item->item_flags = flags & ~(MF_HILITE | MF_MOUSESELECT);
     item->item_id    = id;
+
     SetRectEmpty32( &item->rect );
     if (prevText) HeapFree( SystemHeap, 0, prevText );
     return TRUE;
@@ -1155,14 +1285,14 @@
     MENUITEM *item;
 
     menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
+
     if (menu->FocusedItem == NO_SELECTED_ITEM) return 0;
-    else if (menu->FocusedItem == SYSMENU_SELECTED)
-	return WIN_FindWndPtr(menu->hWnd)->hSysMenu;
 
     item = &menu->items[menu->FocusedItem];
-    if (!(item->item_flags & MF_POPUP) || !(item->item_flags & MF_MOUSESELECT))
-	return 0;
-    return (HMENU32)item->item_id;
+    if ((item->item_flags & (MF_POPUP | MF_MOUSESELECT))
+			 == (MF_POPUP | MF_MOUSESELECT))
+	return (HMENU32)item->item_id;
+    return 0;
 }
 
 
@@ -1174,36 +1304,37 @@
 static void MENU_HideSubPopups( HWND32 hwndOwner, HMENU32 hmenu,
                                 BOOL32 sendMenuSelect )
 {
-    MENUITEM *item;
-    POPUPMENU *menu, *submenu;
-    HMENU32 hsubmenu;
+    POPUPMENU *menu = (POPUPMENU*) USER_HEAP_LIN_ADDR( hmenu );;
 
-    if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return;
-    if (menu->FocusedItem == NO_SELECTED_ITEM) return;
-    if (menu->FocusedItem == SYSMENU_SELECTED)
+    if (menu && uSubPWndLevel)
     {
-	hsubmenu = WIN_FindWndPtr(menu->hWnd)->hSysMenu;
-    }
-    else
-    {
-	item = &menu->items[menu->FocusedItem];
-	if (!(item->item_flags & MF_POPUP) ||
-	    !(item->item_flags & MF_MOUSESELECT)) return;
-	item->item_flags &= ~MF_MOUSESELECT;
-	hsubmenu = (HMENU32)item->item_id;
-    }
-    submenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hsubmenu );
-    MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
-    MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect );
-    if (submenu->hWnd == pTopPWnd->hwndSelf ) 
-    {
-	ShowWindow32( submenu->hWnd, SW_HIDE );
-	uSubPWndLevel = 0;
-    }
-    else
-    {
-	DestroyWindow32( submenu->hWnd );
-	submenu->hWnd = 0;
+	HMENU32 hsubmenu;
+	POPUPMENU *submenu;
+	MENUITEM *item;
+
+	if (menu->FocusedItem != NO_SELECTED_ITEM)
+	{
+	    item = &menu->items[menu->FocusedItem];
+	    if (!(item->item_flags & MF_POPUP) ||
+		!(item->item_flags & MF_MOUSESELECT)) return;
+	    item->item_flags &= ~MF_MOUSESELECT;
+	    hsubmenu = (HMENU32)item->item_id;
+	} else return;
+
+	submenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hsubmenu );
+	MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
+	MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect );
+
+	if (submenu->hWnd == pTopPopupWnd->hwndSelf ) 
+	{
+	    ShowWindow32( submenu->hWnd, SW_HIDE );
+	    uSubPWndLevel = 0;
+	}
+	else
+	{
+	    DestroyWindow32( submenu->hWnd );
+	    submenu->hWnd = 0;
+	}
     }
 }
 
@@ -1217,86 +1348,87 @@
 static HMENU32 MENU_ShowSubPopup( HWND32 hwndOwner, HMENU32 hmenu,
                                   BOOL32 selectFirst )
 {
+    RECT32 rect;
     POPUPMENU *menu;
     MENUITEM *item;
     WND *wndPtr;
 
     if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return hmenu;
-    if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return hmenu;
-    if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
-    if (menu->FocusedItem == SYSMENU_SELECTED)
-    {
-	MENU_InitSysMenuPopup(wndPtr->hSysMenu, wndPtr->dwStyle,
-				wndPtr->class->style);
-	MENU_ShowPopup(hwndOwner, wndPtr->hSysMenu, 0, wndPtr->rectClient.left,
-		wndPtr->rectClient.top - menu->Height - 2*SYSMETRICS_CYBORDER,
-		SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE );
-	if (selectFirst)
-            MENU_SelectItemRel( hwndOwner, wndPtr->hSysMenu, ITEM_NEXT );
-	return wndPtr->hSysMenu;
-    }
+
+    if (!(wndPtr = WIN_FindWndPtr( menu->hWnd )) ||
+         (menu->FocusedItem == NO_SELECTED_ITEM)) return hmenu;
+
     item = &menu->items[menu->FocusedItem];
     if (!(item->item_flags & MF_POPUP) ||
-	(item->item_flags & (MF_GRAYED | MF_DISABLED))) return hmenu;
+         (item->item_flags & (MF_GRAYED | MF_DISABLED))) return hmenu;
     item->item_flags |= MF_MOUSESELECT;
-    if (menu->wFlags & MF_POPUP)
+
+    if (IS_SYSTEM_MENU(menu))
     {
-	MENU_ShowPopup( hwndOwner, (HMENU16)item->item_id, menu->FocusedItem,
-		 wndPtr->rectWindow.left + item->rect.right-arrow_bitmap_width,
-		 wndPtr->rectWindow.top + item->rect.top,
-		 item->rect.left - item->rect.right + 2*arrow_bitmap_width, 
-		 item->rect.top - item->rect.bottom );
+	MENU_InitSysMenuPopup((HMENU16)item->item_id, wndPtr->dwStyle, wndPtr->class->style);
+
+	NC_GetSysPopupPos( wndPtr, &rect );
+	rect.top = rect.bottom;
+	rect.right = SYSMETRICS_CXSIZE; rect.bottom = SYSMETRICS_CYSIZE;
     }
     else
     {
-	MENU_ShowPopup( hwndOwner, (HMENU16)item->item_id, menu->FocusedItem,
-		        wndPtr->rectWindow.left + item->rect.left,
-		        wndPtr->rectWindow.top + item->rect.bottom,
-			item->rect.right - item->rect.left,
-                        item->rect.bottom - item->rect.top );
+	if (menu->wFlags & MF_POPUP)
+	{
+	    rect.left = wndPtr->rectWindow.left + item->rect.right-arrow_bitmap_width;
+	    rect.top = wndPtr->rectWindow.top + item->rect.top;
+	    rect.right = item->rect.left - item->rect.right + 2*arrow_bitmap_width;
+	    rect.bottom = item->rect.top - item->rect.bottom;
+	}
+	else
+	{
+	    rect.left = wndPtr->rectWindow.left + item->rect.left;
+	    rect.top = wndPtr->rectWindow.top + item->rect.bottom;
+	    rect.right = item->rect.right - item->rect.left;
+	    rect.bottom = item->rect.bottom - item->rect.top;
+	}
     }
+
+    MENU_ShowPopup( hwndOwner, (HMENU16)item->item_id, menu->FocusedItem,
+		    rect.left, rect.top, rect.right, rect.bottom );
     if (selectFirst)
-        MENU_SelectItemRel( hwndOwner, (HMENU32)item->item_id, ITEM_NEXT );
+        MENU_MoveSelection( hwndOwner, (HMENU32)item->item_id, ITEM_NEXT );
     return (HMENU32)item->item_id;
 }
 
-
 /***********************************************************************
- *           MENU_FindMenuByCoords
+ *           MENU_PtMenu
  *
- * Find the menu containing a given point (in screen coords).
+ * Walks menu chain trying to find a menu pt maps to.
  */
-static HMENU32 MENU_FindMenuByCoords( HMENU32 hmenu, POINT32 pt )
+static HMENU32 MENU_PtMenu( HMENU32 hMenu, POINT16 pt )
 {
-    POPUPMENU *menu;
-    HWND32 hwnd;
+   POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hMenu );
+   register UINT32 ht = menu->FocusedItem;
 
-    if (!(hwnd = WindowFromPoint32( pt ))) return 0;
-    while (hmenu)
-    {
-	menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
-	if (menu->hWnd == hwnd)
+#define HAS_POPUP(item)	(((item).item_flags & (MF_POPUP | MF_MOUSESELECT)) \
+			== (MF_POPUP | MF_MOUSESELECT))
+   /* try subpopup first (if any) */
+   ht = (ht != NO_SELECTED_ITEM && HAS_POPUP(menu->items[ht]))
+	? (UINT32)MENU_PtMenu( menu->items[ht].item_id, pt ) : 0;
+#undef HAS_POPUP
+
+   if( !ht )	/* check the current window (avoiding WM_HITTEST) */
+   {
+	ht = (UINT32)NC_HandleNCHitTest( menu->hWnd, pt );
+	if( menu->wFlags & MF_POPUP )
+	    ht =  (ht != (UINT32)HTNOWHERE && 
+		   ht != (UINT32)HTERROR) ? (UINT32)hMenu : 0;
+	else
 	{
-	    if (!(menu->wFlags & MF_POPUP))
-	    {
-		  /* Make sure it's in the menu bar (or in system menu) */
-		WND *wndPtr = WIN_FindWndPtr( menu->hWnd );
-		if ((pt.x < wndPtr->rectClient.left) ||
-		    (pt.x >= wndPtr->rectClient.right) ||
-		    (pt.y >= wndPtr->rectClient.top)) return 0;
-		if (pt.y < wndPtr->rectClient.top - menu->Height)
-		{
-		    if (!MENU_IsInSysMenu( menu, pt )) return 0;
-		}
-		/* else it's in the menu bar */
-	    }
-	    return hmenu;
-	}
-	hmenu = MENU_GetSubPopup( hmenu );
-    }
-    return 0;
-}
+	    WND* wndPtr = WIN_FindWndPtr(menu->hWnd);
 
+	    ht = ( ht == HTSYSMENU ) ? (UINT32)(wndPtr->hSysMenu)
+		 : ( ht == HTMENU ) ? (UINT32)(wndPtr->wIDmenu) : 0;
+	}
+   }
+   return (HMENU32)ht;
+}
 
 /***********************************************************************
  *           MENU_ExecFocusedItem
@@ -1304,157 +1436,177 @@
  * Execute a menu item (for instance when user pressed Enter).
  * Return TRUE if we can go on with menu tracking.
  */
-static BOOL32 MENU_ExecFocusedItem( HWND32 hwndOwner, HMENU32 hmenu,
-                                    HMENU32 *hmenuCurrent )
+static BOOL32 MENU_ExecFocusedItem( MTRACKER* pmt, HMENU32 hMenu )
 {
     MENUITEM *item;
-    POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
-    if (!menu || !menu->nItems || (menu->FocusedItem == NO_SELECTED_ITEM) ||
-	(menu->FocusedItem == SYSMENU_SELECTED)) return TRUE;
+    POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hMenu );
+    if (!menu || !menu->nItems || 
+	(menu->FocusedItem == NO_SELECTED_ITEM)) return TRUE;
+
     item = &menu->items[menu->FocusedItem];
     if (!(item->item_flags & MF_POPUP))
     {
 	if (!(item->item_flags & (MF_GRAYED | MF_DISABLED)))
 	{
-	    PostMessage16( hwndOwner, (menu->wFlags & MF_SYSMENU) ? 
-			WM_SYSCOMMAND : WM_COMMAND, item->item_id, 0 );
+	    if( menu->wFlags & MF_SYSMENU )
+	    {
+		PostMessage16( pmt->hOwnerWnd, WM_SYSCOMMAND, item->item_id,
+			       MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
+	    }
+	    else
+		PostMessage16( pmt->hOwnerWnd, WM_COMMAND,
+					item->item_id, 0 );
 	    return FALSE;
 	}
 	else return TRUE;
     }
     else
     {
-	*hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
+	pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hMenu, TRUE );
 	return TRUE;
     }
 }
 
 
 /***********************************************************************
- *           MENU_ButtonDown
+ *           MENU_SwitchTracking
  *
- * Handle a button-down event in a menu. Point is in screen coords.
- * hmenuCurrent is the top-most visible popup.
- * Return TRUE if we can go on with menu tracking.
+ * Helper function for menu navigation routines.
  */
-static BOOL32 MENU_ButtonDown( HWND32 hwndOwner, HMENU32 hmenu,
-                               HMENU32 *hmenuCurrent, POINT32 pt )
+static void MENU_SwitchTracking( MTRACKER* pmt, HMENU32 hPtMenu, UINT32 id )
 {
-    POPUPMENU *menu;
-    MENUITEM *item;
-    UINT32 id;
+    POPUPMENU *ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
+    POPUPMENU *topmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( pmt->hTopMenu );
 
-    if (!hmenu) return FALSE;  /* Outside all menus */
-    menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
-    item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
-    if (!item)  /* Maybe in system menu */
+    if( pmt->hTopMenu != hPtMenu &&
+	!((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
     {
-	if (!MENU_IsInSysMenu( menu, pt )) return FALSE;
-	id = SYSMENU_SELECTED;
-    }	
+	/* both are top level menus (system and menu-bar) */
 
-    if (menu->FocusedItem == id)
-    {
-	if (id == SYSMENU_SELECTED) return FALSE;
-	if (item->item_flags & MF_POPUP)
-	{
-	    if (item->item_flags & MF_MOUSESELECT)
-	    {
-		if (menu->wFlags & MF_POPUP)
-		{
-		    MENU_HideSubPopups( hwndOwner, hmenu, TRUE );
-		    *hmenuCurrent = hmenu;
-		}
-		else return FALSE;
-	    }
-	    else *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
-	}
+	MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
+	MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE );
+        pmt->hTopMenu = hPtMenu;
     }
-    else
-    {
-	MENU_HideSubPopups( hwndOwner, hmenu, FALSE );
-	MENU_SelectItem( hwndOwner, hmenu, id, TRUE );
-	*hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
-    }
-    return TRUE;
+    else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
+    MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE );
 }
 
 
 /***********************************************************************
- *           MENU_ButtonUp
+ *           MENU_ButtonDown
  *
- * Handle a button-up event in a menu. Point is in screen coords.
- * hmenuCurrent is the top-most visible popup.
  * Return TRUE if we can go on with menu tracking.
  */
-static BOOL32 MENU_ButtonUp( HWND32 hwndOwner, HMENU32 hmenu,
-                             HMENU32 *hmenuCurrent, POINT32 pt )
+static BOOL32 MENU_ButtonDown( MTRACKER* pmt, HMENU32 hPtMenu )
 {
-    POPUPMENU *menu;
-    MENUITEM *item;
-    HMENU32 hsubmenu = 0;
-    UINT32 id;
-
-    if (!hmenu) return FALSE;  /* Outside all menus */
-    menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
-    item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
-    if (!item)  /* Maybe in system menu */
+    if (hPtMenu)
     {
-	if (!MENU_IsInSysMenu( menu, pt )) return FALSE;
-	id = SYSMENU_SELECTED;
-	hsubmenu = WIN_FindWndPtr(menu->hWnd)->hSysMenu;
-    }	
+	UINT32 id = 0;
+	POPUPMENU *ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
+	MENUITEM *item;
 
-    if (menu->FocusedItem != id) return FALSE;
+	if( IS_SYSTEM_MENU(ptmenu) )
+	    item = ptmenu->items;
+	else
+	    item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
 
-    if (id != SYSMENU_SELECTED)
-    {
-	if (!(item->item_flags & MF_POPUP))
+	if( item )
 	{
-	    return MENU_ExecFocusedItem( hwndOwner, hmenu, hmenuCurrent );
-	}
-	hsubmenu = (HMENU32)item->item_id;
+	    if( ptmenu->FocusedItem == id )
+	    {
+		/* nothing to do with already selected non-popup */
+		if( !(item->item_flags & MF_POPUP) ) return TRUE;
+
+	        if( item->item_flags & MF_MOUSESELECT )
+		{
+		    if( ptmenu->wFlags & MF_POPUP )
+		    {
+			/* hide selected subpopup */
+
+			MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, TRUE );
+			pmt->hCurrentMenu = hPtMenu;
+			return TRUE;
+		    }
+		    return FALSE; /* shouldn't get here */
+		} 
+	    }
+	    else MENU_SwitchTracking( pmt, hPtMenu, id );
+
+	    /* try to display a subpopup */
+
+	    pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE );
+	    return TRUE;
+	} 
+	else dprintf_menu(stddeb,"\tunable to find clicked item!\n");
     }
-      /* Select first item of sub-popup */
-    MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, FALSE );
-    MENU_SelectItemRel( hwndOwner, hsubmenu, ITEM_NEXT );
-    return TRUE;
+    return FALSE;
+}
+
+/***********************************************************************
+ *           MENU_ButtonUp
+ *
+ * Return TRUE if we can go on with menu tracking.
+ */
+static BOOL32 MENU_ButtonUp( MTRACKER* pmt, HMENU32 hPtMenu )
+{
+    if (hPtMenu)
+    {
+	UINT32 id = 0;
+	POPUPMENU *ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
+	MENUITEM *item;
+
+        if( IS_SYSTEM_MENU(ptmenu) )
+            item = ptmenu->items;
+        else
+            item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
+
+	if( ptmenu->FocusedItem == id )
+	{
+	    if( !(item->item_flags & MF_POPUP) )
+		return MENU_ExecFocusedItem( pmt, hPtMenu );
+	    hPtMenu = (HMENU32)item->item_id;
+	    if( hPtMenu == pmt->hCurrentMenu )
+	    {
+	        /* Select first item of sub-popup */    
+
+	        MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, NO_SELECTED_ITEM, FALSE );
+	        MENU_MoveSelection( pmt->hOwnerWnd, hPtMenu, ITEM_NEXT );
+	    }
+	    return TRUE;
+	}
+    }
+    return FALSE;
 }
 
 
 /***********************************************************************
  *           MENU_MouseMove
  *
- * Handle a motion event in a menu. Point is in screen coords.
- * hmenuCurrent is the top-most visible popup.
  * Return TRUE if we can go on with menu tracking.
  */
-static BOOL32 MENU_MouseMove( HWND32 hwndOwner, HMENU32 hmenu,
-                              HMENU32 *hmenuCurrent, POINT32 pt )
+static BOOL32 MENU_MouseMove( MTRACKER* pmt, HMENU32 hPtMenu )
 {
-    MENUITEM *item;
-    POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
     UINT32 id = NO_SELECTED_ITEM;
+    POPUPMENU *ptmenu = NULL;
 
-    if (hmenu)
+    if( hPtMenu )
     {
-	item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
-	if (!item)  /* Maybe in system menu */
-	{
-	    if (!MENU_IsInSysMenu( menu, pt ))
-		id = NO_SELECTED_ITEM;  /* Outside all items */
-	    else id = SYSMENU_SELECTED;
-	}
-    }	
-    if (id == NO_SELECTED_ITEM)
+	ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
+        if( IS_SYSTEM_MENU(ptmenu) )
+	    id = 0;
+        else
+            MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
+    } 
+
+    if( id == NO_SELECTED_ITEM )
     {
-	MENU_SelectItem( hwndOwner, *hmenuCurrent, NO_SELECTED_ITEM, TRUE );
+	MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu, 
+			 NO_SELECTED_ITEM, TRUE );
     }
-    else if (menu->FocusedItem != id)
+    else if( ptmenu->FocusedItem != id )
     {
-	MENU_HideSubPopups( hwndOwner, hmenu, FALSE );
-	MENU_SelectItem( hwndOwner, hmenu, id, TRUE );
-	*hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
+	    MENU_SwitchTracking( pmt, hPtMenu, id );
+	    pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE );
     }
     return TRUE;
 }
@@ -1462,126 +1614,178 @@
 
 /***********************************************************************
  *           MENU_DoNextMenu
+ *
+ * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
  */
-static LRESULT MENU_DoNextMenu( HWND32* hwndOwner, HMENU32* hmenu,
-                                HMENU32 *hmenuCurrent, UINT32 vk )
+static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT32 vk )
 {
-  POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu );
-  UINT32     id = 0;
+    POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( pmt->hTopMenu );
 
-  if(    (vk == VK_LEFT && !menu->FocusedItem)
-      || (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1) 
-      || menu->FocusedItem == SYSMENU_SELECTED 
-      || ((menu->wFlags & (MF_POPUP | MF_SYSMENU)) == (MF_POPUP | MF_SYSMENU)))
-  {
-    LRESULT l = SendMessage16( *hwndOwner, WM_NEXTMENU, (WPARAM16)vk, 
-                               (LPARAM)((menu->FocusedItem == SYSMENU_SELECTED)
-                                        ? GetSystemMenu32( *hwndOwner, 0) 
-                                        : *hmenu));
+    if( (vk == VK_LEFT &&  menu->FocusedItem == 0 ) ||
+        (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
+    {
+	WND*    wndPtr;
+	HMENU32 hNewMenu;
+	HWND32  hNewWnd;
+	UINT32  id = 0;
+	LRESULT l = SendMessage16( pmt->hOwnerWnd, WM_NEXTMENU, (WPARAM16)vk, 
+		(IS_SYSTEM_MENU(menu)) ? GetSubMenu16(pmt->hTopMenu,0) : pmt->hTopMenu );
 
-    if( l == 0 || !IsMenu32(LOWORD(l)) || !IsWindow32(HIWORD(l)) ) return 0;
+	dprintf_menu(stddeb,"NextMenu: %04x [%04x] -> %04x [%04x]\n",
+		     (UINT16)pmt->hCurrentMenu, (UINT16)pmt->hOwnerWnd, LOWORD(l), HIWORD(l) );
 
-    /* shutdown current menu -
-     * all these checks for system popup window are needed
-     * only because Wine system menu tracking is unsuitable
-     * for a lot of things (esp. when we do not have wIDmenu to fall back on). 
-     */
-
-    MENU_SelectItem( *hwndOwner, *hmenu, NO_SELECTED_ITEM, FALSE );
-
-    if( (menu->wFlags & (MF_POPUP | MF_SYSMENU)) == (MF_POPUP | MF_SYSMENU) )
+	if( l == 0 )
 	{
-	  ShowWindow32( menu->hWnd, SW_HIDE );
-	  uSubPWndLevel = 0;
+	    wndPtr = WIN_FindWndPtr(pmt->hOwnerWnd);
 
-	  if( !IsIconic32( *hwndOwner ) )
-	  { 
-	    HDC32 hdc = GetDCEx32( *hwndOwner, 0, DCX_CACHE | DCX_WINDOW);
-	    NC_DrawSysButton( *hwndOwner, hdc, FALSE );
-	    ReleaseDC32( *hwndOwner, hdc );
-	  }
+	    hNewWnd = pmt->hOwnerWnd;
+	    if( IS_SYSTEM_MENU(menu) )
+	    {
+		/* switch to the menu bar */
+
+		if( wndPtr->dwStyle & WS_CHILD || !wndPtr->wIDmenu ) 
+		    return FALSE;
+
+	        hNewMenu = wndPtr->wIDmenu;
+	        if( vk == VK_LEFT )
+	        {
+		    menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hNewMenu );
+		    id = menu->nItems - 1;
+	        }
+	    }
+	    else if( wndPtr->dwStyle & WS_SYSMENU ) 
+	    {
+		/* switch to the system menu */
+	        hNewMenu = wndPtr->hSysMenu; 
+	    }
+	    else return FALSE;
+	}
+	else    /* application returned a new menu to switch to */
+	{
+	    hNewMenu = LOWORD(l); hNewWnd = HIWORD(l);
+
+	    if( IsMenu32(hNewMenu) && IsWindow32(hNewWnd) )
+	    {
+		wndPtr = WIN_FindWndPtr(hNewWnd);
+
+		if( wndPtr->dwStyle & WS_SYSMENU &&
+		    GetSubMenu16(wndPtr->hSysMenu, 0) == hNewMenu )
+		{
+	            /* get the real system menu */
+		    hNewMenu =  wndPtr->hSysMenu;
+		}
+	        else if( wndPtr->dwStyle & WS_CHILD || wndPtr->wIDmenu != hNewMenu )
+		{
+		    /* FIXME: Not sure what to do here, perhaps,
+		     * try to track hNewMenu as a popup? */
+
+		    dprintf_menu(stddeb,"MENU_DoNextMenu() got confused.\n");
+		    return FALSE;
+		}
+	    }
+	    else return FALSE;
 	}
 
-    ReleaseCapture(); 
-   *hwndOwner = HIWORD(l);
-   *hmenu = LOWORD(l);
-    SetCapture32( *hwndOwner );
+	if( hNewMenu != pmt->hTopMenu )
+	{
+	    MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE );
+	    if( pmt->hCurrentMenu != pmt->hTopMenu ) 
+		MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
+	}
 
-    menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu );
+	if( hNewWnd != pmt->hOwnerWnd )
+	{
+	    ReleaseCapture(); 
+	    pmt->hOwnerWnd = hNewWnd;
+	    EVENT_Capture( pmt->hOwnerWnd, HTMENU );
+	}
 
-    /* init next menu */
+	pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
+	MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE ); 
 
-    if( (menu->wFlags & (MF_POPUP | MF_SYSMENU)) == (MF_POPUP | MF_SYSMENU) )
+	return TRUE;
+    }
+    return FALSE;
+}
+
+/***********************************************************************
+ *           MENU_SuspendPopup
+ *
+ * The idea is not to show the popup if the next input message is
+ * going to hide it anyway.
+ */
+static BOOL32 MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
+{
+    MSG16 msg;
+
+    msg.hwnd = pmt->hOwnerWnd;
+
+    PeekMessage16( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
+    pmt->trackFlags |= TF_SKIPREMOVE;
+
+    switch( uMsg )
     {
-        RECT32 rect;
-        WND*   wndPtr = WIN_FindWndPtr( *hwndOwner );
-
-        /* stupid kludge, see above */
-
-        if( wndPtr->wIDmenu && !(wndPtr->dwStyle & WS_CHILD) )
-        {
-            *hmenu = wndPtr->wIDmenu;
-            id = SYSMENU_SELECTED;
-        }
-        else
-        { 
-            if( NC_GetSysPopupPos( wndPtr, &rect ) )
-                MENU_ShowPopup( *hwndOwner, *hmenu, 0, rect.left, rect.bottom,
-                                SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE );
-            
-            if( !IsIconic32( *hwndOwner ) )
-            {
-                HDC32 hdc =  GetDCEx32( *hwndOwner, 0, DCX_CACHE | DCX_WINDOW);
-                NC_DrawSysButton( *hwndOwner, hdc, TRUE );
-                ReleaseDC32( *hwndOwner, hdc );
-            }
-        }
+	case WM_KEYDOWN:
+	     PeekMessage16( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
+	     if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
+	     {
+		 PeekMessage16( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
+	         PeekMessage16( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
+	         if( msg.message == WM_KEYDOWN &&
+		    (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
+	         {
+		     pmt->trackFlags |= TF_SUSPENDPOPUP;
+		     return TRUE;
+	         }
+	     }
+	     break;
     }
 
-    MENU_SelectItem( *hwndOwner, *hmenu, id, TRUE ); 
-    return l;
-  }
-  return 0;
+    /* failures go through this */
+    pmt->trackFlags &= ~TF_SUSPENDPOPUP;
+    return FALSE;
 }
 
 /***********************************************************************
  *           MENU_KeyLeft
  *
- * Handle a VK_LEFT key event in a menu.
- * hmenuCurrent is the top-most visible popup.
+ * Handle a VK_LEFT key event in a menu. 
  */
-static void MENU_KeyLeft( HWND32* hwndOwner, HMENU32* hmenu,
-                          HMENU32 *hmenuCurrent )
+static void MENU_KeyLeft( MTRACKER* pmt )
 {
     POPUPMENU *menu;
     HMENU32 hmenutmp, hmenuprev;
 
-    menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu );
-    hmenuprev = hmenutmp = *hmenu;
-    while (hmenutmp != *hmenuCurrent)
+    hmenuprev = hmenutmp = pmt->hTopMenu;
+    menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenutmp );
+
+    /* close topmost popup */
+    while (hmenutmp != pmt->hCurrentMenu)
     {
+	hmenuprev = hmenutmp;
 	hmenutmp = MENU_GetSubPopup( hmenuprev );
-	if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
     }
-    MENU_HideSubPopups( *hwndOwner, hmenuprev, TRUE );
-    hmenutmp = *hmenu;
 
-    if ( (hmenuprev == *hmenu) && 
-         ((menu->wFlags & MF_SYSMENU) || !(menu->wFlags & MF_POPUP)) )
+    MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
+    pmt->hCurrentMenu = hmenuprev; 
+
+    if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
     {
-	/* send WM_NEXTMENU */
+	/* move menu bar selection if no more popups are left */
 
-	if( !MENU_DoNextMenu( hwndOwner, hmenu, hmenuCurrent, VK_LEFT) )
-	     MENU_SelectItemRel( *hwndOwner, *hmenu, ITEM_PREV );
-	else *hmenuCurrent = *hmenu;
+	if( !MENU_DoNextMenu( pmt, VK_LEFT) )
+	     MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
 
-	if (*hmenuCurrent != hmenutmp)
+	if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
 	{
-	      /* A sublevel menu was displayed -> display the next one */
-	    *hmenuCurrent = MENU_ShowSubPopup( *hwndOwner, *hmenu, TRUE );
+	   /* A sublevel menu was displayed - display the next one
+	    * unless there is another displacement coming up */
+
+	    if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
+		pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd,
+						pmt->hTopMenu, TRUE );
 	}
     }
-    else *hmenuCurrent = hmenuprev;
 }
 
 
@@ -1589,57 +1793,39 @@
  *           MENU_KeyRight
  *
  * Handle a VK_RIGHT key event in a menu.
- * hmenuCurrent is the top-most visible popup.
  */
-static void MENU_KeyRight( HWND32* hwndOwner, HMENU32* hmenu,
-                           HMENU32 *hmenuCurrent )
+static void MENU_KeyRight( MTRACKER* pmt )
 {
-    POPUPMENU *menu;
     HMENU32 hmenutmp;
+    POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( pmt->hTopMenu );
 
-    menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu );
-
-    if ((menu->wFlags & MF_POPUP) || (*hmenuCurrent != *hmenu))
+    if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
     {
-	  /* If already displaying a popup, try to display sub-popup */
-	hmenutmp = MENU_ShowSubPopup( *hwndOwner, *hmenuCurrent, TRUE );
-	if (hmenutmp != *hmenuCurrent)  /* Sub-popup displayed */
-	{
-	    *hmenuCurrent = hmenutmp;
-	    return;
-	}
+	/* If already displaying a popup, try to display sub-popup */
+
+	hmenutmp = pmt->hCurrentMenu;
+	pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hmenutmp, TRUE );
+
+	/* if subpopup was displayed then we are done */
+	if (hmenutmp != pmt->hCurrentMenu) return;
     }
 
-      /* If menu-bar tracking, go to next item */
-
-    if (!(menu->wFlags & MF_POPUP) || (menu->wFlags & MF_SYSMENU))
+    if (!(menu->wFlags & MF_POPUP))	/* menu bar tracking */
     {
-	MENU_HideSubPopups( *hwndOwner, *hmenu, FALSE );
-	hmenutmp = *hmenu;
-
-        /* Send WM_NEXTMENU */
-
-	if( !MENU_DoNextMenu( hwndOwner, hmenu, hmenuCurrent, VK_RIGHT) )
-	     MENU_SelectItemRel( *hwndOwner, *hmenu, ITEM_NEXT );
-	else *hmenuCurrent = *hmenu;
-
-	if (*hmenuCurrent != hmenutmp)
+	if( pmt->hCurrentMenu != pmt->hTopMenu )
 	{
-	      /* A sublevel menu was displayed -> display the next one */
-	    *hmenuCurrent = MENU_ShowSubPopup( *hwndOwner, *hmenu, TRUE );
-	}
-    }
-    else if (*hmenuCurrent != *hmenu)  /* Hide last level popup */
-    {
-	HMENU16 hmenuprev;
-	hmenuprev = hmenutmp = *hmenu;
-	while (hmenutmp != *hmenuCurrent)
-	{
-	    hmenutmp = MENU_GetSubPopup( hmenuprev );
-	    if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
-	}
-	MENU_HideSubPopups( *hwndOwner, hmenuprev, TRUE );
-	*hmenuCurrent = hmenuprev;
+	    MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
+	    hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
+	} else hmenutmp = 0;
+
+	/* try to move to the next item */
+	if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
+	     MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
+
+	if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
+	    if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
+		pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, 
+						       pmt->hTopMenu, TRUE );
     }
 }
 
@@ -1648,86 +1834,75 @@
  *           MENU_TrackMenu
  *
  * Menu tracking code.
- * If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
- * before beginning tracking. This is to help menu-bar tracking.
  */
 static BOOL32 MENU_TrackMenu( HMENU32 hmenu, UINT32 wFlags, INT32 x, INT32 y,
                               HWND32 hwnd, const RECT32 *lprect )
 {
     MSG16 msg;
     POPUPMENU *menu;
-    HMENU32 hmenuCurrent = hmenu;
-    BOOL32 fClosed = FALSE, fRemove;
-    UINT32 pos;
-    POINT32 pt;
+    BOOL32 fRemove;
+    MTRACKER mt = { 0, hmenu, hmenu, hwnd, {x, y} };	/* control struct */
 
-    fEndMenuCalled = FALSE;
+    fEndMenu = FALSE;
     if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
-    if (x && y)
-    {
-	pt.x = x;
-        pt.y = y;
-	MENU_ButtonDown( hwnd, hmenu, &hmenuCurrent, pt );
-    }
 
-    EVENT_Capture( hwnd, HTMENU );
+    if (wFlags & TPM_BUTTONDOWN) MENU_ButtonDown( &mt, hmenu );
 
-    while (!fClosed)
+    EVENT_Capture( mt.hOwnerWnd, HTMENU );
+
+    while (!fEndMenu)
     {
+	menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( mt.hCurrentMenu );
+	msg.hwnd = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
+
 	/* we have to keep the message in the queue until it's
-	 * clear that menu loop is not over yet.
-	 */
+	 * clear that menu loop is not over yet. */
 
-	if (!MSG_InternalGetMessage( &msg, 0, hwnd, MSGF_MENU, 
-					      PM_NOREMOVE, TRUE ))
-	    break;
+	if (!MSG_InternalGetMessage( &msg, msg.hwnd, mt.hOwnerWnd,
+				     MSGF_MENU, PM_NOREMOVE, TRUE )) break;
 
         TranslateMessage16( &msg );
-        CONV_POINT16TO32( &msg.pt, &pt );
+        CONV_POINT16TO32( &msg.pt, &mt.pt );
 
         fRemove = FALSE;
 	if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
 	{
-	      /* Find the sub-popup for this mouse event (if any) */
+	    /* Find a menu for this mouse event */
 
-	    HMENU32 hsubmenu = MENU_FindMenuByCoords( hmenu, pt );
+	    hmenu = MENU_PtMenu( mt.hTopMenu, msg.pt );
 
 	    switch(msg.message)
 	    {
 		/* no WM_NC... messages in captured state */
 
-	    case WM_RBUTTONDBLCLK:
-	    case WM_RBUTTONDOWN:
-		if (!(wFlags & TPM_RIGHTBUTTON)) break;
-		/* fall through */
-
-	    case WM_LBUTTONDBLCLK:
-	    case WM_LBUTTONDOWN:
-		fClosed = !MENU_ButtonDown( hwnd, hsubmenu,
-					    &hmenuCurrent, pt );
-		break;
+		case WM_RBUTTONDBLCLK:
+		case WM_RBUTTONDOWN:
+		    if (!(wFlags & TPM_RIGHTBUTTON)) break;
+		    /* fall through */
+		case WM_LBUTTONDBLCLK:
+		case WM_LBUTTONDOWN:
+		    fEndMenu |= !MENU_ButtonDown( &mt, hmenu );
+		    break;
 		
-	    case WM_RBUTTONUP:
-		if (!(wFlags & TPM_RIGHTBUTTON)) break;
-		/* fall through */
-
-	    case WM_LBUTTONUP:
-		  /* If outside all menus but inside lprect, ignore it */
-		if (!hsubmenu && lprect && PtInRect32(lprect, pt)) break;
-		fClosed = !MENU_ButtonUp( hwnd, hsubmenu,
-					  &hmenuCurrent, pt );
-                fRemove = TRUE;  /* Remove event even if outside menu */
-		break;
+		case WM_RBUTTONUP:
+		    if (!(wFlags & TPM_RIGHTBUTTON)) break;
+		    /* fall through */
+		case WM_LBUTTONUP:
+		    /* If outside all menus but inside lprect, ignore it */
+		    if (hmenu || !lprect || !PtInRect32(lprect, mt.pt))
+		    {
+			fEndMenu |= !MENU_ButtonUp( &mt, hmenu );
+			fRemove = TRUE; 
+		    }
+		    break;
 		
-	    case WM_MOUSEMOVE:
-		if ((msg.wParam & MK_LBUTTON) ||
-		    ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON)))
-		{
-		    fClosed = !MENU_MouseMove( hwnd, hsubmenu,
-					       &hmenuCurrent, pt );
-		}
-		break;
-	    }
+		case WM_MOUSEMOVE:
+		    if ((msg.wParam & MK_LBUTTON) || ((wFlags & TPM_RIGHTBUTTON) 
+						  && (msg.wParam & MK_RBUTTON)))
+		    {
+			fEndMenu |= !MENU_MouseMove( &mt, hmenu );
+		    }
+	    } /* switch(msg.message) - mouse */
 	}
 	else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
 	{
@@ -1739,39 +1914,38 @@
 		{
 		case VK_HOME:
 		case VK_END:
-		    MENU_SelectItem( hwnd, hmenuCurrent, NO_SELECTED_ITEM, FALSE );
-
+		    MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, 
+				     NO_SELECTED_ITEM, FALSE );
 		/* fall through */
 		case VK_UP:
-		    MENU_SelectItemRel( hwnd, hmenuCurrent, 
+		    MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, 
 				       (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
 		    break;
 
 		case VK_DOWN: /* If on menu bar, pull-down the menu */
 
-		    menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
-		    if (!(menu->wFlags & MF_POPUP) && (hmenuCurrent == hmenu))
-			hmenuCurrent = MENU_ShowSubPopup( hwnd, hmenu, TRUE );
-		    else
-			MENU_SelectItemRel( hwnd, hmenuCurrent, ITEM_NEXT );
+		    menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( mt.hCurrentMenu );
+		    if (!(menu->wFlags & MF_POPUP))
+			mt.hCurrentMenu = MENU_ShowSubPopup( mt.hOwnerWnd, mt.hTopMenu, TRUE );
+		    else      /* otherwise try to move selection */
+			MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
 		    break;
 
 		case VK_LEFT:
-		    MENU_KeyLeft( &hwnd, &hmenu, &hmenuCurrent );
+		    MENU_KeyLeft( &mt );
 		    break;
 		    
 		case VK_RIGHT:
-		    MENU_KeyRight( &hwnd, &hmenu, &hmenuCurrent );
+		    MENU_KeyRight( &mt );
 		    break;
 		    
 		case VK_SPACE:
 		case VK_RETURN:
-		    fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
-						     &hmenuCurrent );
+		    fEndMenu |= !MENU_ExecFocusedItem( &mt, mt.hCurrentMenu );
 		    break;
 
 		case VK_ESCAPE:
-		    fClosed = TRUE;
+		    fEndMenu = TRUE;
 		    break;
 
 		default:
@@ -1783,7 +1957,7 @@
 		switch(msg.wParam)
 		{
 		case VK_MENU:
-		    fClosed = TRUE;
+		    fEndMenu = TRUE;
 		    break;
 		    
 		}
@@ -1791,81 +1965,58 @@
 
 	    case WM_CHAR:
 		{
+		    UINT32	pos;
+
 		      /* Hack to avoid control chars. */
 		      /* We will find a better way real soon... */
 		    if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
-		    pos = MENU_FindItemByKey( hwnd, hmenuCurrent, msg.wParam, FALSE );
-		    if (pos == (UINT32)-2) fClosed = TRUE;
+
+		    pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu, 
+							msg.wParam, FALSE );
+		    if (pos == (UINT32)-2) fEndMenu = TRUE;
 		    else if (pos == (UINT32)-1) MessageBeep32(0);
 		    else
 		    {
-			MENU_SelectItem( hwnd, hmenuCurrent, pos, TRUE );
-			fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
-							 &hmenuCurrent );
-			
+			MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos, TRUE );
+			fEndMenu |= !MENU_ExecFocusedItem( &mt, mt.hCurrentMenu );
 		    }
 		}		    
-		break;  /* WM_CHAR */
-	    }  /* switch(msg.message) */
+		break;
+	    }  /* switch(msg.message) - kbd */
 	}
 	else
 	{
 	    DispatchMessage16( &msg );
 	}
-	if (fEndMenuCalled) fClosed = TRUE;
-	if (!fClosed) fRemove = TRUE;
 
-        if (fRemove)  /* Remove the message from the queue */
+	if (!fEndMenu) fRemove = TRUE;
+
+	/* finally remove message from the queue */
+
+        if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
 	    PeekMessage16( &msg, 0, msg.message, msg.message, PM_REMOVE );
+	else mt.trackFlags &= ~TF_SKIPREMOVE;
     }
 
     ReleaseCapture();
-    MENU_HideSubPopups( hwnd, hmenu, FALSE );
-    menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
-    if (menu && menu->wFlags & MF_POPUP) 
+    if( IsWindow32( mt.hOwnerWnd ) )
     {
-         ShowWindow32( menu->hWnd, SW_HIDE );
-	 uSubPWndLevel = 0;
+	MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
+
+	menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( mt.hTopMenu );
+	if (menu && menu->wFlags & MF_POPUP) 
+	{
+	    ShowWindow32( menu->hWnd, SW_HIDE );
+	    uSubPWndLevel = 0;
+	}
+	MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE );
+	SendMessage16( mt.hOwnerWnd, WM_MENUSELECT, 0, MAKELONG( 0xffff, 0 ) );
     }
-    MENU_SelectItem( hwnd, hmenu, NO_SELECTED_ITEM, FALSE );
-    SendMessage16( hwnd, WM_MENUSELECT, 0, MAKELONG( 0xffff, 0 ) );
-    fEndMenuCalled = FALSE;
+    fEndMenu = FALSE;
     return TRUE;
 }
 
 /***********************************************************************
- *           MENU_TrackSysPopup
- */
-static void MENU_TrackSysPopup( WND* pWnd )
-{
-    RECT32  rect;
-    HMENU32 hMenu = pWnd->hSysMenu;
-    HDC32   hDC = 0;
-
-    /* track the system menu like a normal popup menu */
-
-    if(IsMenu32(hMenu))
-    {
-	HWND32 hWnd = pWnd->hwndSelf;
-	if (!(pWnd->dwStyle & WS_MINIMIZE))
-	{
-	    hDC = GetWindowDC32( hWnd );
-	    NC_DrawSysButton( hWnd, hDC, TRUE );
-	}
-	NC_GetSysPopupPos( pWnd, &rect );
-	MENU_InitSysMenuPopup( hMenu, pWnd->dwStyle,
-				      pWnd->class->style);
-	TrackPopupMenu32( hMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
-                          rect.left, rect.bottom, 0, hWnd, &rect );
-	if (!(pWnd->dwStyle & WS_MINIMIZE))
-	{
-             NC_DrawSysButton( hWnd, hDC, FALSE );
-             ReleaseDC32( hWnd, hDC );
-	}
-    }
-}
-
-/***********************************************************************
  *           MENU_InitTracking
  */
 static BOOL32 MENU_InitTracking(HWND32 hWnd, HMENU32 hMenu)
@@ -1884,19 +2035,15 @@
  */
 void MENU_TrackMouseMenuBar( WND* wndPtr, INT32 ht, POINT32 pt )
 {
-    BOOL32  bTrackSys = ((ht == HTSYSMENU && !wndPtr->wIDmenu) ||
-                         (wndPtr->dwStyle & (WS_MINIMIZE | WS_CHILD)));
     HWND32  hWnd = wndPtr->hwndSelf;
-    HMENU32 hMenu = (bTrackSys) ? wndPtr->hSysMenu : wndPtr->wIDmenu;
+    HMENU32 hMenu = (ht == HTSYSMENU) ? wndPtr->hSysMenu : wndPtr->wIDmenu;
 
     if (IsMenu32(hMenu))
     {
 	MENU_InitTracking( hWnd, hMenu );
-	if( bTrackSys )
-	    MENU_TrackSysPopup( wndPtr );
-	else
-	    MENU_TrackMenu( hMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
-			    pt.x, pt.y, hWnd, NULL );
+	MENU_TrackMenu( hMenu, TPM_ENTERIDLEEX | TPM_BUTTONDOWN | 
+		        TPM_LEFTALIGN | TPM_LEFTBUTTON, pt.x, pt.y, hWnd, NULL );
+
 	SendMessage16( hWnd, WM_EXITMENULOOP, 0, 0 );
 	ShowCaret32(0);
     }
@@ -1910,7 +2057,6 @@
  */
 void MENU_TrackKbdMenuBar( WND* wndPtr, UINT32 wParam, INT32 vkey)
 {
-   INT32 htMenu;
    UINT32 uItem = NO_SELECTED_ITEM;
    HMENU32 hTrackMenu; 
 
@@ -1918,54 +2064,47 @@
  
     while( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwStyle & WS_SYSMENU) )
 	if( !(wndPtr = wndPtr->parent) ) return;
-          
-    if( !wndPtr->wIDmenu && !(wndPtr->dwStyle & WS_SYSMENU) ) return;
 
-    if((wndPtr->dwStyle & (WS_CHILD | WS_MINIMIZE)) || !wndPtr->wIDmenu) 
+    /* check if we have to track a system menu */
+          
+    if( (wndPtr->dwStyle & (WS_CHILD | WS_MINIMIZE)) || 
+	!wndPtr->wIDmenu || vkey == VK_SPACE )
     {
+	if( !(wndPtr->dwStyle & WS_SYSMENU) ) return;
 	hTrackMenu = wndPtr->hSysMenu;
-	htMenu = HTSYSMENU;
+	uItem = 0;
+	wParam |= HTSYSMENU;	/* prevent item lookup */
     }
     else
-    {
 	hTrackMenu = wndPtr->wIDmenu;
-	htMenu = HTMENU;
-    }
 
     if (IsMenu32( hTrackMenu ))
     {
 	MENU_InitTracking( wndPtr->hwndSelf, hTrackMenu );
 
-        if( vkey == VK_SPACE )
-            uItem = SYSMENU_SELECTED;
-        else if( vkey )
+        if( vkey && vkey != VK_SPACE )
         {
             uItem = MENU_FindItemByKey( wndPtr->hwndSelf, hTrackMenu, 
-					vkey, (htMenu == HTSYSMENU) );
+					vkey, (wParam & HTSYSMENU) );
 	    if( uItem >= (UINT32)(-2) )
 	    {
 	        if( uItem == (UINT32)(-1) ) MessageBeep32(0);
-		htMenu = 0;
+		hTrackMenu = 0;
 	    }
         }
 
-	switch( htMenu )
+	if( hTrackMenu )
 	{
-	    case HTMENU:
- 		MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE );
-		if( uItem == NO_SELECTED_ITEM )
-		    MENU_SelectItemRel( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT );
-		else
-		    PostMessage16( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L );
+ 	    MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE );
 
-		MENU_TrackMenu( hTrackMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
-				0, 0, wndPtr->hwndSelf, NULL );
-		break;
+	    if( uItem == NO_SELECTED_ITEM )
+		MENU_MoveSelection( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT );
+	    else if( vkey )
+		PostMessage16( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L );
 
-	    case HTSYSMENU:
-		MENU_TrackSysPopup( wndPtr );
+	    MENU_TrackMenu( hTrackMenu, TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON,
+			    0, 0, wndPtr->hwndSelf, NULL );
 	}
-
         SendMessage16( wndPtr->hwndSelf, WM_EXITMENULOOP, 0, 0 );
         ShowCaret32(0);
     }
@@ -1996,7 +2135,7 @@
 
     HideCaret32(0);
     if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 )) 
-	ret = MENU_TrackMenu( hMenu, wFlags, 0, 0, hWnd, lpRect );
+	ret = MENU_TrackMenu( hMenu, wFlags & ~TPM_INTERNAL, 0, 0, hWnd, lpRect );
     ShowCaret32(0);
     return ret;
 }
@@ -2014,10 +2153,14 @@
 
 /***********************************************************************
  *           PopupMenuWndProc
+ *
+ * NOTE: Windows has totally different (and undocumented) popup wndproc.
  */
 LRESULT PopupMenuWndProc( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
                           LPARAM lParam )
 {    
+    WND* wndPtr = WIN_FindWndPtr(hwnd);
+
     switch(message)
     {
     case WM_CREATE:
@@ -2039,21 +2182,45 @@
 	    EndPaint32( hwnd, &ps );
 	    return 0;
 	}
+    case WM_ERASEBKGND:
+	return 1;
 
     case WM_DESTROY:
-	    /* zero out global pointer in case system popup
-	     * was destroyed by AppExit 
-	     */
 
-	    if( hwnd == pTopPWnd->hwndSelf )
-	    {	pTopPWnd = NULL; uSubPWndLevel = 0; }
-	    else
-		uSubPWndLevel--;
-	    break;
+	/* zero out global pointer in case resident popup window
+	 * was somehow destroyed. */
 
-    case WM_USER:
-	if (wParam) SetWindowLong32A( hwnd, 0, (HMENU16)wParam );
+	if( hwnd == pTopPopupWnd->hwndSelf )
+	{	
+	    dprintf_menu(stddeb,"resident popup destroyed!\n");
+
+	    pTopPopupWnd = NULL; 
+	    uSubPWndLevel = 0; 
+	}
+	else
+	    uSubPWndLevel--;
+	break;
+
+    case WM_SHOWWINDOW:
+
+	if( wParam )
+	{
+	    if( !(*(HMENU32*)wndPtr->wExtra) )
+		fprintf(stderr,"MenuWndProc: no menu to display\n");
+	}
+	else
+	    *(HMENU32*)wndPtr->wExtra = 0;
+	break;
+
+    case MM_SETMENUHANDLE:
+
+	*(HMENU32*)wndPtr->wExtra = (HMENU32)wParam;
         break;
+
+    case MM_GETMENUHANDLE:
+
+	return *(HMENU32*)wndPtr->wExtra;
+
     default:
 	return DefWindowProc32A( hwnd, message, wParam, lParam );
     }
@@ -2095,9 +2262,11 @@
                   hMenu, pos, (DWORD)data, id, flags );
     if (flags & MF_APPEND) return AppendMenu16( hMenu, flags & ~MF_APPEND,
                                                 id, data );
+
     /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
     /* for MF_DELETE. We should check the parameters for all others */
     /* MF_* actions also (anybody got a doc on ChangeMenu?). */
+
     if (flags & MF_DELETE) return DeleteMenu16(hMenu, pos, flags & ~MF_DELETE);
     if (flags & MF_CHANGE) return ModifyMenu16(hMenu, pos, flags & ~MF_CHANGE,
                                                id, data );
@@ -2425,8 +2594,7 @@
     if (flags & MF_POPUP)  /* Set the MF_POPUP flag on the popup-menu */
 	((POPUPMENU *)USER_HEAP_LIN_ADDR((HMENU16)id))->wFlags |= MF_POPUP;
 
-    item->hCheckBit   = hStdCheck;
-    item->hUnCheckBit = 0;
+    item->pCB = NULL;
     return TRUE;
 }
 
@@ -2500,8 +2668,8 @@
     
       /* Remove item */
 
-    if (IS_STRING_ITEM(item->item_flags) && item->text)
-        HeapFree( SystemHeap, 0, item->text );
+    MENU_FreeItemData( item );
+
     if (--menu->nItems == 0)
     {
         HeapFree( SystemHeap, 0, menu->items );
@@ -2658,15 +2826,16 @@
 
     if (!hNewCheck && !hNewUnCheck)
     {
-	  /* If both are NULL, restore default bitmaps */
-	item->hCheckBit   = hStdCheck;
-	item->hUnCheckBit = 0;
+	if( item->pCB ) HeapFree( SystemHeap, 0, item->pCB );
+	item->pCB = NULL;
 	item->item_flags &= ~MF_USECHECKBITMAPS;
     }
     else  /* Install new bitmaps */
     {
-	item->hCheckBit   = hNewCheck;
-	item->hUnCheckBit = hNewUnCheck;
+	if( item->pCB == NULL ) 
+	    item->pCB = HeapAlloc( SystemHeap, 0, sizeof(CBITMAPS));
+	item->pCB->hCheckBit = hNewCheck;
+	item->pCB->hUnCheckBit = hNewUnCheck;
 	item->item_flags |= MF_USECHECKBITMAPS;
     }
     return TRUE;
@@ -2719,35 +2888,42 @@
  */
 BOOL32 DestroyMenu32( HMENU32 hMenu )
 {
-    LPPOPUPMENU lppop;
     dprintf_menu(stddeb,"DestroyMenu(%04x)\n", hMenu);
 
-    if (hMenu == 0) return FALSE;
-    /* Silently ignore attempts to destroy default system menu */
-    if (hMenu == MENU_DefSysMenu) return TRUE;
-    lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
-    if (!lppop || (lppop->wMagic != MENU_MAGIC)) return FALSE;
-    lppop->wMagic = 0;  /* Mark it as destroyed */
-    if ((lppop->wFlags & MF_POPUP) &&
-        lppop->hWnd &&
-        (!pTopPWnd || (lppop->hWnd != pTopPWnd->hwndSelf)))
-        DestroyWindow32( lppop->hWnd );
+    /* Silently ignore attempts to destroy default system popup */
 
-    if (lppop->items)
+    if (hMenu && hMenu != MENU_DefSysPopup)
     {
-        int i;
-        MENUITEM *item = lppop->items;
-        for (i = lppop->nItems; i > 0; i--, item++)
-        {
-            if (item->item_flags & MF_POPUP)
-                DestroyMenu32( (HMENU32)item->item_id );
-	    if (IS_STRING_ITEM(item->item_flags) && item->text)
-                HeapFree( SystemHeap, 0, item->text );
-        }
-        HeapFree( SystemHeap, 0, lppop->items );
+	LPPOPUPMENU lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
+
+	if( pTopPopupWnd && (hMenu == *(HMENU32*)pTopPopupWnd->wExtra) )
+	  *(UINT32*)pTopPopupWnd->wExtra = 0;
+
+	if (lppop && (lppop->wMagic == MENU_MAGIC))
+	{
+	    lppop->wMagic = 0;  /* Mark it as destroyed */
+
+	    if ((lppop->wFlags & MF_POPUP) && lppop->hWnd &&
+	        (!pTopPopupWnd || (lppop->hWnd != pTopPopupWnd->hwndSelf)))
+	        DestroyWindow32( lppop->hWnd );
+
+	    if (lppop->items)	/* recursively destroy submenus */
+	    {
+	        int i;
+	        MENUITEM *item = lppop->items;
+	        for (i = lppop->nItems; i > 0; i--, item++)
+	        {
+	            if (item->item_flags & MF_POPUP)
+	                DestroyMenu32( (HMENU32)item->item_id );
+		    MENU_FreeItemData( item );
+	        }
+	        HeapFree( SystemHeap, 0, lppop->items );
+	    }
+	    USER_HEAP_FREE( hMenu );
+	}
+	else return FALSE;
     }
-    USER_HEAP_FREE( hMenu );
-    return TRUE;
+    return (hMenu != MENU_DefSysPopup);
 }
 
 
@@ -2766,17 +2942,32 @@
 HMENU32 GetSystemMenu32( HWND32 hWnd, BOOL32 bRevert )
 {
     WND *wndPtr = WIN_FindWndPtr( hWnd );
-    if (!wndPtr) return 0;
 
-    if (!wndPtr->hSysMenu || (wndPtr->hSysMenu == MENU_DefSysMenu))
+    if (wndPtr)
     {
-        wndPtr->hSysMenu = MENU_CopySysMenu();
-        return wndPtr->hSysMenu;
+	if( wndPtr->hSysMenu )
+	{
+	    if( bRevert )
+	    {
+		DestroyMenu32(wndPtr->hSysMenu); 
+		wndPtr->hSysMenu = 0;
+	    }
+	    else
+	    {
+		POPUPMENU *menu = (POPUPMENU*) 
+			   USER_HEAP_LIN_ADDR(wndPtr->hSysMenu);
+		if( menu->items[0].item_id == MENU_DefSysPopup )
+		    menu->items[0].item_id = MENU_CopySysPopup();
+	    }
+	}
+
+	if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
+	    wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU32)(-1) );
+
+	if( wndPtr->hSysMenu )
+	    return GetSubMenu16(wndPtr->hSysMenu, 0);
     }
-    if (!bRevert) return wndPtr->hSysMenu;
-    if (wndPtr->hSysMenu) DestroyMenu32(wndPtr->hSysMenu);
-    wndPtr->hSysMenu = MENU_CopySysMenu();
-    return wndPtr->hSysMenu;
+    return 0;
 }
 
 
@@ -2794,13 +2985,15 @@
  */
 BOOL32 SetSystemMenu32( HWND32 hwnd, HMENU32 hMenu )
 {
-    WND *wndPtr;
+    WND *wndPtr = WIN_FindWndPtr(hwnd);
 
-    if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
-    if (wndPtr->hSysMenu && (wndPtr->hSysMenu != MENU_DefSysMenu))
-        DestroyMenu32( wndPtr->hSysMenu );
-    wndPtr->hSysMenu = hMenu;
-    return TRUE;
+    if (wndPtr)
+    {
+	if (wndPtr->hSysMenu) DestroyMenu32( wndPtr->hSysMenu );
+	wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
+	return TRUE;
+    }
+    return FALSE;
 }
 
 
@@ -2810,7 +3003,8 @@
 HMENU16 GetMenu16( HWND16 hWnd ) 
 {
     WND * wndPtr = WIN_FindWndPtr(hWnd);
-    if (wndPtr) return (HMENU16)wndPtr->wIDmenu;
+    if (wndPtr && !(wndPtr->dwStyle & WS_CHILD)) 
+	return (HMENU16)wndPtr->wIDmenu;
     return 0;
 }
 
@@ -2821,7 +3015,8 @@
 HMENU32 GetMenu32( HWND32 hWnd ) 
 { 
     WND * wndPtr = WIN_FindWndPtr(hWnd);
-    if (wndPtr) return (HMENU32)wndPtr->wIDmenu;
+    if (wndPtr && !(wndPtr->dwStyle & WS_CHILD)) 
+	return (HMENU32)wndPtr->wIDmenu;
     return 0;
 }
 
@@ -2840,23 +3035,30 @@
  */
 BOOL32 SetMenu32( HWND32 hWnd, HMENU32 hMenu )
 {
-    LPPOPUPMENU lpmenu;
     WND * wndPtr = WIN_FindWndPtr(hWnd);
-    if (!wndPtr) return FALSE;
+
     dprintf_menu(stddeb,"SetMenu(%04x, %04x);\n", hWnd, hMenu);
-    if (GetCapture32() == hWnd) ReleaseCapture();
-    wndPtr->wIDmenu = (UINT32)hMenu;
-    if (hMenu != 0)
+
+    if (wndPtr && !(wndPtr->dwStyle & WS_CHILD))
     {
-        if (!(lpmenu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
-        lpmenu->hWnd = hWnd;
-        lpmenu->wFlags &= ~MF_POPUP;  /* Can't be a popup */
-        lpmenu->Height = 0;  /* Make sure we recalculate the size */
-    }
-    if (IsWindowVisible32(hWnd))
-        SetWindowPos32( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
+	if (GetCapture32() == hWnd) ReleaseCapture();
+
+	wndPtr->wIDmenu = (UINT32)hMenu;
+	if (hMenu != 0)
+	{
+	    LPPOPUPMENU lpmenu;
+
+            if (!(lpmenu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
+            lpmenu->hWnd = hWnd;
+            lpmenu->wFlags &= ~MF_POPUP;  /* Can't be a popup */
+            lpmenu->Height = 0;  /* Make sure we recalculate the size */
+	}
+	if (IsWindowVisible32(hWnd))
+            SetWindowPos32( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
                         SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
-    return TRUE;
+	return TRUE;
+    }
+    return FALSE;
 }
 
 
@@ -2919,8 +3121,7 @@
  */
 void EndMenu(void)
 {
-    /* FIXME: this won't work when we have multiple tasks... */
-    fEndMenuCalled = TRUE;
+    fEndMenu = TRUE;
 }
 
 
diff --git a/controls/widgets.c b/controls/widgets.c
index 04769d9..729bd6d 100644
--- a/controls/widgets.c
+++ b/controls/widgets.c
@@ -76,7 +76,7 @@
       ComboLBWndProc, 0, sizeof(void *), 0, 0, IDC_ARROW, 0, 0, "ComboLBox" },
     /* BIC32_POPUPMENU */
     { CS_GLOBALCLASS | CS_SAVEBITS, PopupMenuWndProc,
-      0, sizeof(HMENU32), 0, 0, IDC_ARROW, 0, 0, POPUPMENU_CLASS_NAME },
+      0, sizeof(HMENU32), 0, 0, IDC_ARROW, NULL_BRUSH, 0, POPUPMENU_CLASS_NAME },
     /* BIC32_SCROLL */
     { CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC,
       ScrollBarWndProc, 0, sizeof(SCROLLBAR_INFO), 0, 0, IDC_ARROW, 0, 0, "ScrollBar"},
diff --git a/debugger/db_disasm.c b/debugger/db_disasm.c
index 32e0d44..715ddbe 100644
--- a/debugger/db_disasm.c
+++ b/debugger/db_disasm.c
@@ -1531,7 +1531,7 @@
 		      }
 
 		    if (seg)
-			fprintf(stderr,"%s:%d",seg, displ);
+			fprintf(stderr,"%s:0x%x",seg, displ);
 		    else
 			db_task_printsym(displ, short_addr ? WORD : LONG);
 		    break;
diff --git a/documentation/winsock b/documentation/winsock
index d8c497e..a6e41bf 100644
--- a/documentation/winsock
+++ b/documentation/winsock
@@ -1,3 +1,5 @@
+----- Information in this file is obsolete. -----
+
 Winsock
 
 Platform 1.
diff --git a/files/file.c b/files/file.c
index 641957f..1ff6c21 100644
--- a/files/file.c
+++ b/files/file.c
@@ -981,10 +981,17 @@
     if (count == 0)  /* Expand or truncate at current position */
         result = ftruncate( file->unix_handle,
                             lseek( file->unix_handle, 0, SEEK_CUR ) );
-    else
+    else for (;;)
+    {
         result = write( file->unix_handle, buffer, count );
+        if (result != -1) break;
+        if (errno != EINTR)
+        {
+            FILE_SetDosError();
+            break;
+        }
+    }
 
-    if (result == -1) FILE_SetDosError();
     FILE_ReleaseFile( file );
     return result;
 }
diff --git a/graphics/wing.c b/graphics/wing.c
index aed0e39..90321e5 100644
--- a/graphics/wing.c
+++ b/graphics/wing.c
@@ -20,6 +20,8 @@
 #include "stddebug.h"
 #include "debug.h"
 
+extern void CLIPPING_UpdateGCRegion(DC* );
+
 typedef enum WING_DITHER_TYPE
 {
   WING_DISPERSED_4x4, WING_DISPERSED_8x8, WING_CLUSTERED_4x4
diff --git a/graphics/x11drv/bitmap.c b/graphics/x11drv/bitmap.c
index b302248..33bf1f6 100644
--- a/graphics/x11drv/bitmap.c
+++ b/graphics/x11drv/bitmap.c
@@ -16,6 +16,8 @@
 #include "stddebug.h"
 #include "debug.h"
 
+extern void CLIPPING_UpdateGCRegion(DC* );
+
 /***********************************************************************
  *           X11DRV_BITMAP_Init
  */
diff --git a/graphics/x11drv/font.c b/graphics/x11drv/font.c
index 0d4e2c6..7826db6 100644
--- a/graphics/x11drv/font.c
+++ b/graphics/x11drv/font.c
@@ -332,6 +332,9 @@
 
 /***********************************************************************
  *           X11DRV_FONT_SelectObject
+ *
+ * FIXME: the fonts should not be cached by hfont only, because
+ * metrics may be different in an other DC.
  */
 HFONT32 X11DRV_FONT_SelectObject( DC * dc, HFONT32 hfont, FONTOBJ * font )
 {
diff --git a/if1632/mmsystem.spec b/if1632/mmsystem.spec
index 482ff50..c0f75d1 100644
--- a/if1632/mmsystem.spec
+++ b/if1632/mmsystem.spec
@@ -55,7 +55,7 @@
 401    pascal  WAVEOUTGETNUMDEVS() waveOutGetNumDevs
 402    pascal  WAVEOUTGETDEVCAPS(word segptr word) waveOutGetDevCaps
 403    pascal  WAVEOUTGETERRORTEXT(word ptr word) waveOutGetErrorText
-404    pascal  WAVEOUTOPEN(ptr word ptr long long long) waveOutOpen
+404    pascal  WAVEOUTOPEN(ptr word segptr long long long) waveOutOpen
 405    pascal  WAVEOUTCLOSE(word) waveOutClose
 406    pascal  WAVEOUTPREPAREHEADER(word segptr word) waveOutPrepareHeader
 407    pascal  WAVEOUTUNPREPAREHEADER(word segptr word) waveOutUnprepareHeader
@@ -76,7 +76,7 @@
 501    pascal  WAVEINGETNUMDEVS() waveInGetNumDevs
 502    pascal  WAVEINGETDEVCAPS(word segptr word) waveInGetDevCaps
 503    pascal  WAVEINGETERRORTEXT(word ptr word) waveInGetErrorText
-504    pascal  WAVEINOPEN(ptr word ptr long long long) waveInOpen
+504    pascal  WAVEINOPEN(ptr word segptr long long long) waveInOpen
 505    pascal  WAVEINCLOSE(word) waveInClose
 506    pascal  WAVEINPREPAREHEADER(word segptr word) waveInPrepareHeader
 507    pascal  WAVEINUNPREPAREHEADER(word segptr word) waveInUnprepareHeader
diff --git a/if1632/winsock.spec b/if1632/winsock.spec
index fea16ef..3961ed7 100644
--- a/if1632/winsock.spec
+++ b/if1632/winsock.spec
@@ -50,7 +50,7 @@
 107 pascal16 WSAAsyncGetServByName(word word ptr ptr segptr word)
              WSAAsyncGetServByName
 108 pascal16 WSACancelAsyncRequest(word) WSACancelAsyncRequest
-109 pascal16 WSASetBlockingHook() WSASetBlockingHook
+109 pascal16 WSASetBlockingHook(segptr) WSASetBlockingHook16
 110 pascal16 WSAUnhookBlockingHook() WSAUnhookBlockingHook
 111 pascal16 WSAGetLastError() WSAGetLastError
 112 pascal   WSASetLastError(word) WSASetLastError
diff --git a/if1632/wsock32.spec b/if1632/wsock32.spec
index f868690..c7597e2 100644
--- a/if1632/wsock32.spec
+++ b/if1632/wsock32.spec
@@ -40,7 +40,7 @@
 106 stub WSAAsyncGetServByPort
 107 stub WSAAsyncGetServByName
 108 stub WSACancelAsyncRequest
-109 stub WSASetBlockingHook
+109 stdcall WSASetBlockingHook(ptr) WSASetBlockingHook32
 110 stub WSAUnhookBlockingHook
 111 stub WSAGetLastError
 112 stub WSASetLastError
diff --git a/include/bitmap.h b/include/bitmap.h
index 72dc215..3b8bfe2 100644
--- a/include/bitmap.h
+++ b/include/bitmap.h
@@ -42,7 +42,7 @@
 
 #define XCREATEIMAGE(image,width,height,bpp) \
 { \
-    int width_bytes = DIB_GetImageWidthBytesX11( (width), (bpp) ); \
+    int width_bytes = DIB_GetXImageWidthBytes( (width), (bpp) ); \
     (image) = XCreateImage(display, DefaultVisualOfScreen(screen), \
                            (bpp), ZPixmap, 0, xmalloc( (height)*width_bytes ),\
                            (width), (height), 32, width_bytes ); \
@@ -55,8 +55,8 @@
 extern BOOL32 BITMAP_DeleteObject( HBITMAP16 hbitmap, BITMAPOBJ * bitmap );
 
   /* objects/dib.c */
-extern int DIB_GetImageWidthBytes( int width, int depth );
-extern int DIB_GetImageWidthBytesX11( int width, int depth );
+extern int DIB_GetDIBWidthBytes( int width, int depth );
+extern int DIB_GetXImageWidthBytes( int width, int depth );
 extern int DIB_BitmapInfoSize( BITMAPINFO * info, WORD coloruse );
 
   /* objects/oembitmap.c */
diff --git a/include/color.h b/include/color.h
index 1bd269b..94be6f3 100644
--- a/include/color.h
+++ b/include/color.h
@@ -8,6 +8,7 @@
 #define COLOR_VIRTUAL   0x0002          /* no mapping needed - pixel == pixel color */
 
 #define COLOR_PRIVATE   0x1000          /* private colormap, identity mapping */
+#define COLOR_WHITESET	0x2000
 
 #define PC_SYS_USED     0x80		/* palentry is used (both system and logical) */
 #define PC_SYS_RESERVED 0x40		/* system palentry is not to be mapped to */
@@ -22,6 +23,7 @@
 extern Colormap	  COLOR_GetColormap();
 extern UINT16	  COLOR_GetSystemPaletteSize();
 extern UINT16	  COLOR_GetSystemPaletteFlags();
+extern BOOL32	  COLOR_GetMonoPlane( int* );
 
 extern COLORREF	  COLOR_LookupNearestColor( PALETTEENTRY*, int, COLORREF );
 extern int        COLOR_PaletteLookupPixel( PALETTEENTRY*, int, int* , COLORREF, BOOL32 );
diff --git a/include/debug.h b/include/debug.h
index dd40d37..55a01ea 100644
--- a/include/debug.h
+++ b/include/debug.h
@@ -53,6 +53,7 @@
 #undef DEBUG_MESSAGE
 #undef DEBUG_METAFILE
 #undef DEBUG_MIDI
+#undef DEBUG_MMAUX
 #undef DEBUG_MMIO
 #undef DEBUG_MMSYS
 #undef DEBUG_MMTIME
@@ -135,6 +136,7 @@
 #define DEBUG_MESSAGE
 #define DEBUG_METAFILE
 #define DEBUG_MIDI
+#define DEBUG_MMAUX
 #define DEBUG_MMIO
 #define DEBUG_MMSYS
 #define DEBUG_MMTIME
@@ -407,6 +409,11 @@
 #else
     0,
 #endif
+#ifdef DEBUG_MMAUX
+    1,
+#else
+    0,
+#endif
 #ifdef DEBUG_MMIO
     1,
 #else
@@ -1186,8 +1193,21 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_mmio if(!debug_msg_enabled[47]) ; else fprintf
-#define debugging_mmio debug_msg_enabled[47]
+#define dprintf_mmaux if(!debug_msg_enabled[47]) ; else fprintf
+#define debugging_mmaux debug_msg_enabled[47]
+#else
+#ifdef DEBUG_MMAUX
+#define dprintf_mmaux fprintf
+#define debugging_mmaux 1
+#else
+#define dprintf_mmaux while(0) fprintf
+#define debugging_mmaux 0
+#endif
+#endif
+
+#ifdef DEBUG_RUNTIME
+#define dprintf_mmio if(!debug_msg_enabled[48]) ; else fprintf
+#define debugging_mmio debug_msg_enabled[48]
 #else
 #ifdef DEBUG_MMIO
 #define dprintf_mmio fprintf
@@ -1199,8 +1219,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_mmsys if(!debug_msg_enabled[48]) ; else fprintf
-#define debugging_mmsys debug_msg_enabled[48]
+#define dprintf_mmsys if(!debug_msg_enabled[49]) ; else fprintf
+#define debugging_mmsys debug_msg_enabled[49]
 #else
 #ifdef DEBUG_MMSYS
 #define dprintf_mmsys fprintf
@@ -1212,8 +1232,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_mmtime if(!debug_msg_enabled[49]) ; else fprintf
-#define debugging_mmtime debug_msg_enabled[49]
+#define dprintf_mmtime if(!debug_msg_enabled[50]) ; else fprintf
+#define debugging_mmtime debug_msg_enabled[50]
 #else
 #ifdef DEBUG_MMTIME
 #define dprintf_mmtime fprintf
@@ -1225,8 +1245,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_module if(!debug_msg_enabled[50]) ; else fprintf
-#define debugging_module debug_msg_enabled[50]
+#define dprintf_module if(!debug_msg_enabled[51]) ; else fprintf
+#define debugging_module debug_msg_enabled[51]
 #else
 #ifdef DEBUG_MODULE
 #define dprintf_module fprintf
@@ -1238,8 +1258,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_msg if(!debug_msg_enabled[51]) ; else fprintf
-#define debugging_msg debug_msg_enabled[51]
+#define dprintf_msg if(!debug_msg_enabled[52]) ; else fprintf
+#define debugging_msg debug_msg_enabled[52]
 #else
 #ifdef DEBUG_MSG
 #define dprintf_msg fprintf
@@ -1251,8 +1271,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_nonclient if(!debug_msg_enabled[52]) ; else fprintf
-#define debugging_nonclient debug_msg_enabled[52]
+#define dprintf_nonclient if(!debug_msg_enabled[53]) ; else fprintf
+#define debugging_nonclient debug_msg_enabled[53]
 #else
 #ifdef DEBUG_NONCLIENT
 #define dprintf_nonclient fprintf
@@ -1264,8 +1284,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_ole if(!debug_msg_enabled[53]) ; else fprintf
-#define debugging_ole debug_msg_enabled[53]
+#define dprintf_ole if(!debug_msg_enabled[54]) ; else fprintf
+#define debugging_ole debug_msg_enabled[54]
 #else
 #ifdef DEBUG_OLE
 #define dprintf_ole fprintf
@@ -1277,8 +1297,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_palette if(!debug_msg_enabled[54]) ; else fprintf
-#define debugging_palette debug_msg_enabled[54]
+#define dprintf_palette if(!debug_msg_enabled[55]) ; else fprintf
+#define debugging_palette debug_msg_enabled[55]
 #else
 #ifdef DEBUG_PALETTE
 #define dprintf_palette fprintf
@@ -1290,8 +1310,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_profile if(!debug_msg_enabled[55]) ; else fprintf
-#define debugging_profile debug_msg_enabled[55]
+#define dprintf_profile if(!debug_msg_enabled[56]) ; else fprintf
+#define debugging_profile debug_msg_enabled[56]
 #else
 #ifdef DEBUG_PROFILE
 #define dprintf_profile fprintf
@@ -1303,8 +1323,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_prop if(!debug_msg_enabled[56]) ; else fprintf
-#define debugging_prop debug_msg_enabled[56]
+#define dprintf_prop if(!debug_msg_enabled[57]) ; else fprintf
+#define debugging_prop debug_msg_enabled[57]
 #else
 #ifdef DEBUG_PROP
 #define dprintf_prop fprintf
@@ -1316,8 +1336,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_reg if(!debug_msg_enabled[57]) ; else fprintf
-#define debugging_reg debug_msg_enabled[57]
+#define dprintf_reg if(!debug_msg_enabled[58]) ; else fprintf
+#define debugging_reg debug_msg_enabled[58]
 #else
 #ifdef DEBUG_REG
 #define dprintf_reg fprintf
@@ -1329,8 +1349,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_region if(!debug_msg_enabled[58]) ; else fprintf
-#define debugging_region debug_msg_enabled[58]
+#define dprintf_region if(!debug_msg_enabled[59]) ; else fprintf
+#define debugging_region debug_msg_enabled[59]
 #else
 #ifdef DEBUG_REGION
 #define dprintf_region fprintf
@@ -1342,8 +1362,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_relay if(!debug_msg_enabled[59]) ; else fprintf
-#define debugging_relay debug_msg_enabled[59]
+#define dprintf_relay if(!debug_msg_enabled[60]) ; else fprintf
+#define debugging_relay debug_msg_enabled[60]
 #else
 #ifdef DEBUG_RELAY
 #define dprintf_relay fprintf
@@ -1355,8 +1375,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_resource if(!debug_msg_enabled[60]) ; else fprintf
-#define debugging_resource debug_msg_enabled[60]
+#define dprintf_resource if(!debug_msg_enabled[61]) ; else fprintf
+#define debugging_resource debug_msg_enabled[61]
 #else
 #ifdef DEBUG_RESOURCE
 #define dprintf_resource fprintf
@@ -1368,8 +1388,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_scroll if(!debug_msg_enabled[61]) ; else fprintf
-#define debugging_scroll debug_msg_enabled[61]
+#define dprintf_scroll if(!debug_msg_enabled[62]) ; else fprintf
+#define debugging_scroll debug_msg_enabled[62]
 #else
 #ifdef DEBUG_SCROLL
 #define dprintf_scroll fprintf
@@ -1381,8 +1401,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_selector if(!debug_msg_enabled[62]) ; else fprintf
-#define debugging_selector debug_msg_enabled[62]
+#define dprintf_selector if(!debug_msg_enabled[63]) ; else fprintf
+#define debugging_selector debug_msg_enabled[63]
 #else
 #ifdef DEBUG_SELECTOR
 #define dprintf_selector fprintf
@@ -1394,8 +1414,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_sem if(!debug_msg_enabled[63]) ; else fprintf
-#define debugging_sem debug_msg_enabled[63]
+#define dprintf_sem if(!debug_msg_enabled[64]) ; else fprintf
+#define debugging_sem debug_msg_enabled[64]
 #else
 #ifdef DEBUG_SEM
 #define dprintf_sem fprintf
@@ -1407,8 +1427,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_sendmsg if(!debug_msg_enabled[64]) ; else fprintf
-#define debugging_sendmsg debug_msg_enabled[64]
+#define dprintf_sendmsg if(!debug_msg_enabled[65]) ; else fprintf
+#define debugging_sendmsg debug_msg_enabled[65]
 #else
 #ifdef DEBUG_SENDMSG
 #define dprintf_sendmsg fprintf
@@ -1420,8 +1440,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_shm if(!debug_msg_enabled[65]) ; else fprintf
-#define debugging_shm debug_msg_enabled[65]
+#define dprintf_shm if(!debug_msg_enabled[66]) ; else fprintf
+#define debugging_shm debug_msg_enabled[66]
 #else
 #ifdef DEBUG_SHM
 #define dprintf_shm fprintf
@@ -1433,8 +1453,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_stress if(!debug_msg_enabled[66]) ; else fprintf
-#define debugging_stress debug_msg_enabled[66]
+#define dprintf_stress if(!debug_msg_enabled[67]) ; else fprintf
+#define debugging_stress debug_msg_enabled[67]
 #else
 #ifdef DEBUG_STRESS
 #define dprintf_stress fprintf
@@ -1446,8 +1466,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_string if(!debug_msg_enabled[67]) ; else fprintf
-#define debugging_string debug_msg_enabled[67]
+#define dprintf_string if(!debug_msg_enabled[68]) ; else fprintf
+#define debugging_string debug_msg_enabled[68]
 #else
 #ifdef DEBUG_STRING
 #define dprintf_string fprintf
@@ -1459,8 +1479,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_task if(!debug_msg_enabled[68]) ; else fprintf
-#define debugging_task debug_msg_enabled[68]
+#define dprintf_task if(!debug_msg_enabled[69]) ; else fprintf
+#define debugging_task debug_msg_enabled[69]
 #else
 #ifdef DEBUG_TASK
 #define dprintf_task fprintf
@@ -1472,8 +1492,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_text if(!debug_msg_enabled[69]) ; else fprintf
-#define debugging_text debug_msg_enabled[69]
+#define dprintf_text if(!debug_msg_enabled[70]) ; else fprintf
+#define debugging_text debug_msg_enabled[70]
 #else
 #ifdef DEBUG_TEXT
 #define dprintf_text fprintf
@@ -1485,8 +1505,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_timer if(!debug_msg_enabled[70]) ; else fprintf
-#define debugging_timer debug_msg_enabled[70]
+#define dprintf_timer if(!debug_msg_enabled[71]) ; else fprintf
+#define debugging_timer debug_msg_enabled[71]
 #else
 #ifdef DEBUG_TIMER
 #define dprintf_timer fprintf
@@ -1498,8 +1518,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_toolhelp if(!debug_msg_enabled[71]) ; else fprintf
-#define debugging_toolhelp debug_msg_enabled[71]
+#define dprintf_toolhelp if(!debug_msg_enabled[72]) ; else fprintf
+#define debugging_toolhelp debug_msg_enabled[72]
 #else
 #ifdef DEBUG_TOOLHELP
 #define dprintf_toolhelp fprintf
@@ -1511,8 +1531,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_ver if(!debug_msg_enabled[72]) ; else fprintf
-#define debugging_ver debug_msg_enabled[72]
+#define dprintf_ver if(!debug_msg_enabled[73]) ; else fprintf
+#define debugging_ver debug_msg_enabled[73]
 #else
 #ifdef DEBUG_VER
 #define dprintf_ver fprintf
@@ -1524,8 +1544,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_virtual if(!debug_msg_enabled[73]) ; else fprintf
-#define debugging_virtual debug_msg_enabled[73]
+#define dprintf_virtual if(!debug_msg_enabled[74]) ; else fprintf
+#define debugging_virtual debug_msg_enabled[74]
 #else
 #ifdef DEBUG_VIRTUAL
 #define dprintf_virtual fprintf
@@ -1537,8 +1557,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_vxd if(!debug_msg_enabled[74]) ; else fprintf
-#define debugging_vxd debug_msg_enabled[74]
+#define dprintf_vxd if(!debug_msg_enabled[75]) ; else fprintf
+#define debugging_vxd debug_msg_enabled[75]
 #else
 #ifdef DEBUG_VXD
 #define dprintf_vxd fprintf
@@ -1550,8 +1570,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_win if(!debug_msg_enabled[75]) ; else fprintf
-#define debugging_win debug_msg_enabled[75]
+#define dprintf_win if(!debug_msg_enabled[76]) ; else fprintf
+#define debugging_win debug_msg_enabled[76]
 #else
 #ifdef DEBUG_WIN
 #define dprintf_win fprintf
@@ -1563,8 +1583,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_win16drv if(!debug_msg_enabled[76]) ; else fprintf
-#define debugging_win16drv debug_msg_enabled[76]
+#define dprintf_win16drv if(!debug_msg_enabled[77]) ; else fprintf
+#define debugging_win16drv debug_msg_enabled[77]
 #else
 #ifdef DEBUG_WIN16DRV
 #define dprintf_win16drv fprintf
@@ -1576,8 +1596,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_win32 if(!debug_msg_enabled[77]) ; else fprintf
-#define debugging_win32 debug_msg_enabled[77]
+#define dprintf_win32 if(!debug_msg_enabled[78]) ; else fprintf
+#define debugging_win32 debug_msg_enabled[78]
 #else
 #ifdef DEBUG_WIN32
 #define dprintf_win32 fprintf
@@ -1589,8 +1609,8 @@
 #endif
 
 #ifdef DEBUG_RUNTIME
-#define dprintf_winsock if(!debug_msg_enabled[78]) ; else fprintf
-#define debugging_winsock debug_msg_enabled[78]
+#define dprintf_winsock if(!debug_msg_enabled[79]) ; else fprintf
+#define debugging_winsock debug_msg_enabled[79]
 #else
 #ifdef DEBUG_WINSOCK
 #define dprintf_winsock fprintf
@@ -1652,6 +1672,7 @@
     "message",
     "metafile",
     "midi",
+    "mmaux",
     "mmio",
     "mmsys",
     "mmtime",
diff --git a/include/graphics.h b/include/graphics.h
index 6d933fd..00d963a 100644
--- a/include/graphics.h
+++ b/include/graphics.h
@@ -18,7 +18,7 @@
 				 INT32 width, INT32 height, HPEN32 hPen);
 extern BOOL32 GRAPH_DrawBitmap( HDC32 hdc, HBITMAP32 hbitmap,
                                 INT32 xdest, INT32 ydest, INT32 xsrc,
-                                INT32 ysrc, INT32 width, INT32 height );
+                                INT32 ysrc, INT32 width, INT32 height, BOOL32 bMono );
 extern BOOL32 GRAPH_SelectClipMask( HDC32 hdc, HBITMAP32 hMono,
                                     INT32 x, INT32 y );
 
diff --git a/include/mdi.h b/include/mdi.h
index 0ad2700..4915730 100644
--- a/include/mdi.h
+++ b/include/mdi.h
@@ -31,15 +31,15 @@
 
 typedef struct 
 {
-    WORD   	nActiveChildren;
+    UINT16   	nActiveChildren;
     HWND16   	hwndChildMaximized;
     HWND16   	hwndActiveChild;
     HMENU16  	hWindowMenu;
-    WORD   	idFirstChild;
-    WORD	nTotalCreated;
+    UINT32   	idFirstChild;
     LPSTR 	frameTitle;
-    WORD   	sbNeedUpdate;
-    WORD   	sbRecalc;
+    UINT16	nTotalCreated;
+    UINT16   	mdiFlags;
+    UINT16   	sbRecalc;		/* SB_xxx flags for scrollbar fixup */
     HWND16   	self;
 } MDICLIENTINFO;
 
diff --git a/include/menu.h b/include/menu.h
index 69ef851..121c091 100644
--- a/include/menu.h
+++ b/include/menu.h
@@ -6,7 +6,7 @@
 #define __WINE_MENU_H
 
 extern BOOL32 MENU_Init(void);
-extern HMENU32 MENU_GetDefSysMenu(void);
+extern HMENU32 MENU_GetSysMenu(HWND32 hWndOwner, HMENU32 hSysPopup);
 extern void MENU_InitSysMenuPopup(HMENU32 hmenu, DWORD style, DWORD clsStyle);
 extern UINT32 MENU_GetMenuBarHeight( HWND32 hwnd, UINT32 menubarWidth,
                                      INT32 orgX, INT32 orgY );
diff --git a/include/mmsystem.h b/include/mmsystem.h
index 56bc611..cc138fe 100644
--- a/include/mmsystem.h
+++ b/include/mmsystem.h
@@ -1485,6 +1485,7 @@
 	LPWAVEFORMAT	lpFormat;
 	DWORD			dwCallBack;
 	DWORD			dwInstance;
+	UINT16                  uDeviceID;
 } WAVEOPENDESC, *LPWAVEOPENDESC;
 
 typedef struct {
diff --git a/include/queue.h b/include/queue.h
index 3010784..80fe77d 100644
--- a/include/queue.h
+++ b/include/queue.h
@@ -75,8 +75,8 @@
 
 extern void QUEUE_DumpQueue( HQUEUE16 hQueue );
 extern void QUEUE_WalkQueues(void);
-extern BOOL32 QUEUE_IsDoomedQueue( HQUEUE16 hQueue );
-extern void QUEUE_SetDoomedQueue( HQUEUE16 hQueue );
+extern BOOL32 QUEUE_IsExitingQueue( HQUEUE16 hQueue );
+extern void QUEUE_SetExitingQueue( HQUEUE16 hQueue );
 extern MESSAGEQUEUE *QUEUE_GetSysQueue(void);
 extern void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit );
 extern void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit );
@@ -95,5 +95,6 @@
 extern void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos );
 extern void hardware_event( WORD message, WORD wParam, LONG lParam,
 			    int xPos, int yPos, DWORD time, DWORD extraInfo );
+extern void QUEUE_FlushMessages( HQUEUE16 hQueue );
 
 #endif  /* __WINE_QUEUE_H */
diff --git a/include/stddebug.h b/include/stddebug.h
index 98177e0..e05112d 100644
--- a/include/stddebug.h
+++ b/include/stddebug.h
@@ -123,6 +123,7 @@
 #undef DEBUG_MESSAGE
 #undef DEBUG_METAFILE
 #undef DEBUG_MIDI
+#undef DEBUG_MMAUX
 #undef DEBUG_MMIO
 #undef DEBUG_MMSYS
 #undef DEBUG_MMTIME
@@ -205,6 +206,7 @@
 #define DEBUG_MESSAGE
 #define DEBUG_METAFILE
 #define DEBUG_MIDI
+#define DEBUG_MMAUX
 #define DEBUG_MMIO
 #define DEBUG_MMSYS
 #define DEBUG_MMTIME
diff --git a/loader/ne_image.c b/loader/ne_image.c
index ec82673..d5f1e80 100644
--- a/loader/ne_image.c
+++ b/loader/ne_image.c
@@ -281,7 +281,13 @@
 
 	offset  = rep->offset;
 
-	switch (rep->address_type)
+        /* Apparently, high bit of address_type is sometimes set; */
+        /* we ignore it for now */
+	if (rep->address_type & 0x80)
+            fprintf( stderr, "Warning: reloc addr type = 0x%02x\n",
+                     rep->address_type );
+
+	switch (rep->address_type & 0x7f)
 	{
 	  case NE_RADDR_LOWBYTE:
             do {
@@ -415,12 +421,16 @@
                 {
                     if (*p & 0x0002)
                     {
-			if (pModule->flags & NE_FFLAGS_MULTIPLEDATA) {
+			if (pModule->flags & NE_FFLAGS_MULTIPLEDATA)
+                        {
 			    /* can this happen? */
 			    fprintf( stderr, "FixupPrologs got confused\n" );
 			}
-                        *fixup_ptr = 0xb8;	/* MOV AX, */
-                        *(WORD *)(fixup_ptr+1) = dgroup;
+                        else if (pModule->flags & NE_FFLAGS_SINGLEDATA)
+                        {
+                            *fixup_ptr = 0xb8;	/* MOV AX, */
+                            *(WORD *)(fixup_ptr+1) = dgroup;
+                        }
                     }
                     else
                     {
diff --git a/memory/global.c b/memory/global.c
index f5d7d18..749d284 100644
--- a/memory/global.c
+++ b/memory/global.c
@@ -872,7 +872,7 @@
       pintern=HeapAlloc(GetProcessHeap(), 0,  sizeof(GLOBAL32_INTERN));
       if(size)
       {
-	 palloc=HeapAlloc(GetProcessHeap(), 0, size+sizeof(HGLOBAL32));
+	 palloc=HeapAlloc(GetProcessHeap(), hpflags, size+sizeof(HGLOBAL32));
 	 *(HGLOBAL32 *)palloc=INTERN_TO_HANDLE(pintern);
 	 pintern->Pointer=palloc+sizeof(HGLOBAL32);
       }
diff --git a/misc/commdlg.c b/misc/commdlg.c
index 07ced79..2f053da 100644
--- a/misc/commdlg.c
+++ b/misc/commdlg.c
@@ -202,7 +202,8 @@
     len = strlen(str);
     GetDlgItemText32A( hWnd, edt1, str + len, sizeof(str) - len );
     if (!DlgDirList32A( hWnd, str, lst1, 0, 0x0000 )) return FALSE;
-    return DlgDirList32A( hWnd, "*.*", lst2, stc1, 0x8010 );
+    strcpy( str, "*.*" );
+    return DlgDirList32A( hWnd, str, lst2, stc1, 0x8010 );
 }
 
 /***********************************************************************
@@ -409,7 +410,8 @@
   			lpofn->nFilterIndex, tmpstr);
   SetDlgItemText32A( hWnd, edt1, tmpstr );
   /* get drive list */
-  DlgDirListComboBox32A(hWnd, "", cmb2, 0, 0xC000);
+  *tmpstr = 0;
+  DlgDirListComboBox32A(hWnd, tmpstr, cmb2, 0, 0xC000);
   /* read initial directory */
   if (PTR_SEG_TO_LIN(lpofn->lpstrInitialDir) != NULL) 
     {
diff --git a/misc/crtdll.c b/misc/crtdll.c
index f9ab8c0..60d3aeb 100644
--- a/misc/crtdll.c
+++ b/misc/crtdll.c
@@ -25,6 +25,8 @@
 #include "crtdll.h"
 #include "drive.h"
 
+extern INT32 WIN32_wsprintf32W( DWORD *args );
+
 UINT32 CRTDLL_argc_dll;         /* CRTDLL.23 */
 LPSTR *CRTDLL_argv_dll;         /* CRTDLL.24 */
 LPSTR  CRTDLL_acmdln_dll;       /* CRTDLL.38 */
diff --git a/misc/winsock.c b/misc/winsock.c
index b250184..926c514 100644
--- a/misc/winsock.c
+++ b/misc/winsock.c
@@ -628,19 +628,31 @@
 
     switch( cmd )
     {
-	case WS_FIONREAD:   newcmd=FIONREAD; break;
-	case WS_FIONBIO:    newcmd=FIONBIO;  
-			    if( pws->p_aop && *argp == 0 ) 
-			    { 
-				pwsi->err = WSAEINVAL; 
-				return SOCKET_ERROR; 
-			    }
-			    break;
-	case WS_SIOCATMARK: newcmd=SIOCATMARK; break;
+	case WS_FIONREAD:   
+		newcmd=FIONREAD; 
+		break;
+
+	case WS_FIONBIO:    
+		newcmd=FIONBIO;  
+		if( pws->p_aop && *argp == 0 ) 
+		{
+		    pwsi->err = WSAEINVAL; 
+		    return SOCKET_ERROR; 
+		}
+		break;
+
+	case WS_SIOCATMARK: 
+		newcmd=SIOCATMARK; 
+		break;
+
 	case WS_IOW('f',125,u_long): 
-			  fprintf(stderr,"Warning: WS1.1 shouldn't be using async I/O\n");
-			  pwsi->err = WSAEINVAL; return SOCKET_ERROR;
-	default:	  fprintf(stderr,"Warning: Unknown WS_IOCTL cmd (%08x)\n", cmd);
+		fprintf(stderr,"Warning: WS1.1 shouldn't be using async I/O\n");
+		pwsi->err = WSAEINVAL; 
+		return SOCKET_ERROR;
+
+	default:	  
+		/* Netscape tries hard to use bogus ioctl 0x667e */
+		dprintf_winsock(stddeb,"\tunknown WS_IOCTL cmd (%08x)\n", cmd);
     }
     if( ioctl(pws->fd, newcmd, (char*)argp ) == 0 ) return 0;
     pwsi->err = (errno == EBADF) ? WSAENOTSOCK : wsaErrno(); 
@@ -1429,7 +1441,7 @@
   return SOCKET_ERROR;
 }
 
-FARPROC16 WSASetBlockingHook(FARPROC16 lpBlockFunc)
+FARPROC16 WSASetBlockingHook16(FARPROC16 lpBlockFunc)
 {
   FARPROC16		prev;
   LPWSINFO              pwsi = wsi_find(GetCurrentTask());
@@ -1445,6 +1457,12 @@
   return 0;
 }
 
+FARPROC32 WSASetBlockingHook32(FARPROC32 lpBlockFunc)
+{
+    fprintf( stderr, "Empty stub WSASetBlockingHook32(%p)\n", lpBlockFunc );
+    return NULL;
+}
+
 INT16 WSAUnhookBlockingHook(void)
 {
   LPWSINFO              pwsi = wsi_find(GetCurrentTask());
diff --git a/misc/wsprintf.c b/misc/wsprintf.c
index bdb6713..4ca4828 100644
--- a/misc/wsprintf.c
+++ b/misc/wsprintf.c
@@ -524,7 +524,7 @@
 }
 
 /* Emulator version */
-INT32 WIN32_wsprintf32A( int *args )
+INT32 WIN32_wsprintf32A( DWORD *args )
 {
     return wvsprintf32A( (LPSTR)args[0], (LPCSTR)args[1], (LPCVOID)&args[2] );
 }
@@ -546,7 +546,7 @@
 }
 
 /* Emulator version */
-INT32 WIN32_wsprintf32W( int *args )
+INT32 WIN32_wsprintf32W( DWORD *args )
 {
     return wvsprintf32W( (LPWSTR)args[0], (LPCWSTR)args[1], (LPCVOID)&args[2]);
 }
diff --git a/msdos/dpmi.c b/msdos/dpmi.c
index 408e6dc..05404ce 100644
--- a/msdos/dpmi.c
+++ b/msdos/dpmi.c
@@ -20,6 +20,8 @@
 
 #define DOS_GET_DRIVE(reg) ((reg) ? (reg) - 1 : DRIVE_GetCurrentDrive())
 
+void CreateBPB(int drive, BYTE *data);  /* defined in int21.c */
+
 
 /* Structure for real-mode callbacks */
 typedef struct
diff --git a/multimedia/audio.c b/multimedia/audio.c
index 558466f..31af318 100644
--- a/multimedia/audio.c
+++ b/multimedia/audio.c
@@ -26,10 +26,9 @@
 #include "stddebug.h"
 #include "debug.h"
 
-int MMSYSTEM_DevIDToIndex(UINT16);
-
 #if defined(linux) || defined(__FreeBSD__)
 #define SOUND_DEV "/dev/dsp"
+#define MIXER_DEV "/dev/mixer"
 
 #ifdef SOUND_VERSION
 #define IOCTL(a,b,c)		((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
@@ -37,42 +36,43 @@
 #define IOCTL(a,b,c)		(c = ioctl(a,b,c) )
 #endif
 
-#define MAX_WAVOUTDRV 	2
-#define MAX_WAVINDRV 	2
-#define MAX_MCIWAVDRV 	2
+#define MAX_WAVOUTDRV 	(1)
+#define MAX_WAVINDRV 	(1)
+#define MAX_MCIWAVDRV 	(1)
 
 typedef struct {
-	int				unixdev;
-	int				state;
-	DWORD			bufsize;
-	WAVEOPENDESC	waveDesc;
-	WORD			wFlags;
-	PCMWAVEFORMAT	Format;
-	LPWAVEHDR 		lpQueueHdr;
-	DWORD			dwTotalPlayed;
+	int		    unixdev;
+	int		    state;
+	DWORD		    bufsize;
+	WAVEOPENDESC        waveDesc;
+	WORD                wFlags;
+	PCMWAVEFORMAT	    Format;
+	LPWAVEHDR 	    lpQueueHdr;
+	DWORD		    dwTotalPlayed;
 	} LINUX_WAVEOUT;
 
 typedef struct {
-	int				unixdev;
-	int				state;
-	DWORD			bufsize;	/* Linux '/dev/dsp' give us that size */
-	WAVEOPENDESC	waveDesc;
-	WORD			wFlags;
-	PCMWAVEFORMAT	Format;
-	LPWAVEHDR 		lpQueueHdr;
-	DWORD			dwTotalRecorded;
+	int	            unixdev;
+	int	            state;
+	DWORD               bufsize;            /* Linux '/dev/dsp' give us that size */
+	WAVEOPENDESC        waveDesc;
+	WORD                wFlags;
+	PCMWAVEFORMAT       Format;
+	LPWAVEHDR           lpQueueHdr;
+	DWORD               dwTotalRecorded;
 	} LINUX_WAVEIN;
 
 typedef struct {
-    int     nUseCount;          /* Incremented for each shared open */
-    BOOL16  fShareable;         /* TRUE if first open was shareable */
-    WORD    wNotifyDeviceID;    /* MCI device ID with a pending notification */
-    HANDLE16 hCallback;          /* Callback handle for pending notification */
-	HMMIO16	hFile;				/* mmio file handle open as Element		*/
+        int                 nUseCount;          /* Incremented for each shared open */
+	BOOL16              fShareable;         /* TRUE if first open was shareable */
+	WORD                wNotifyDeviceID;    /* MCI device ID with a pending notification */
+	HANDLE16            hCallback;          /* Callback handle for pending notification */
+	HMMIO16	            hFile;		/* mmio file handle open as Element */
 	MCI_WAVE_OPEN_PARMS openParms;
-	PCMWAVEFORMAT	WaveFormat;
-	WAVEHDR		WaveHdr;
-	} LINUX_MCIWAVE;
+	PCMWAVEFORMAT       WaveFormat;
+	WAVEHDR             WaveHdr;
+	BOOL16              fInput;             /* FALSE = Output, TRUE = Input */
+} LINUX_MCIWAVE;
 
 static LINUX_WAVEOUT	WOutDev[MAX_WAVOUTDRV];
 static LINUX_WAVEIN	WInDev[MAX_WAVOUTDRV];
@@ -85,12 +85,14 @@
 static DWORD WAVE_NotifyClient(UINT16 wDevID, WORD wMsg, 
 				DWORD dwParam1, DWORD dwParam2)
 {
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
+	dprintf_mciwave(stddeb,"WAVE_NotifyClient // wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",wDevID, wMsg, dwParam1, dwParam2);
 
-	if (WInDev[index].wFlags != DCB_NULL && !DriverCallback(
-		WInDev[index].waveDesc.dwCallBack, WInDev[index].wFlags, 
-		WInDev[index].waveDesc.hWave, wMsg, 
-		WInDev[index].waveDesc.dwInstance, dwParam1, dwParam2)) {
+	if (wDevID > MAX_WAVOUTDRV) return MCIERR_INTERNAL;
+
+	if (WInDev[wDevID].wFlags != DCB_NULL && !DriverCallback(
+		WInDev[wDevID].waveDesc.dwCallBack, WInDev[wDevID].wFlags, 
+		WInDev[wDevID].waveDesc.hWave, wMsg, 
+		WInDev[wDevID].waveDesc.dwInstance, dwParam1, dwParam2)) {
 		dprintf_mciwave(stddeb,"WAVE_NotifyClient // can't notify client !\n");
 		return MMSYSERR_NOERROR;
 		}
@@ -99,11 +101,11 @@
 
 
 /**************************************************************************
-* 				WAVE_mciOpen	*/
+ * 				WAVE_mciOpen	                        [internal]*/
 static DWORD WAVE_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMS lpParms)
 {
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
-	HLOCAL16	hFormat;
+	HLOCAL16        hFormat;
+	LPWAVEFORMAT    lpFormat;
 	LPPCMWAVEFORMAT	lpWaveFormat;
 	HLOCAL16	hDesc;
 	LPWAVEOPENDESC 	lpDesc;
@@ -115,23 +117,22 @@
 				wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
 
-	wDevID = lpParms->wDeviceID;
-	index = MMSYSTEM_DevIDToIndex(wDevID);
-
-	if (MCIWavDev[index].nUseCount > 0) {
+	if (MCIWavDev[wDevID].nUseCount > 0) {
 		/* The driver already open on this channel */
 		/* If the driver was opened shareable before and this open specifies */
 		/* shareable then increment the use count */
-		if (MCIWavDev[index].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
-			++MCIWavDev[index].nUseCount;
+		if (MCIWavDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
+			++MCIWavDev[wDevID].nUseCount;
 		else
 			return MCIERR_MUST_USE_SHAREABLE;
 		}
 	else {
-		MCIWavDev[index].nUseCount = 1;
-		MCIWavDev[index].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
+		MCIWavDev[wDevID].nUseCount = 1;
+		MCIWavDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
 		}
-	lpParms->wDeviceID = wDevID;
+
+	MCIWavDev[wDevID].fInput = FALSE;
+
 	dprintf_mciwave(stddeb,"WAVE_mciOpen // wDevID=%04X\n", wDevID);
 	dprintf_mciwave(stddeb,"WAVE_mciOpen // before OPEN_ELEMENT\n");
 	if (dwFlags & MCI_OPEN_ELEMENT) {
@@ -141,20 +142,20 @@
 		if (strlen(lpstrElementName) > 0) {
 			strcpy(str, lpstrElementName);
 			CharUpper32A(str);
-			MCIWavDev[index].hFile = mmioOpen(str, NULL, 
+			MCIWavDev[wDevID].hFile = mmioOpen(str, NULL, 
 				MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE);
-			if (MCIWavDev[index].hFile == 0) {
+			if (MCIWavDev[wDevID].hFile == 0) {
 				dprintf_mciwave(stddeb,"WAVE_mciOpen // can't find file='%s' !\n", str);
 				return MCIERR_FILE_NOT_FOUND;
 				}
 			}
 		else 
-			MCIWavDev[index].hFile = 0;
+			MCIWavDev[wDevID].hFile = 0;
 		}
-	dprintf_mciwave(stddeb,"WAVE_mciOpen // hFile=%u\n", MCIWavDev[index].hFile);
-	memcpy(&MCIWavDev[index].openParms, lpParms, sizeof(MCI_WAVE_OPEN_PARMS));
-	MCIWavDev[index].wNotifyDeviceID = lpParms->wDeviceID;
-	lpWaveFormat = &MCIWavDev[index].WaveFormat;
+	dprintf_mciwave(stddeb,"WAVE_mciOpen // hFile=%u\n", MCIWavDev[wDevID].hFile);
+	memcpy(&MCIWavDev[wDevID].openParms, lpParms, sizeof(MCI_WAVE_OPEN_PARMS));
+	MCIWavDev[wDevID].wNotifyDeviceID = lpParms->wDeviceID;
+	lpWaveFormat = &MCIWavDev[wDevID].WaveFormat;
 	hDesc = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hDesc);
 	lpDesc->hWave = 0;
@@ -166,10 +167,10 @@
 	lpWaveFormat->wf.nAvgBytesPerSec = 11025;
 	lpWaveFormat->wf.nBlockAlign = 1;
 */
-	if (MCIWavDev[index].hFile != 0) {
+	if (MCIWavDev[wDevID].hFile != 0) {
 		MMCKINFO	mmckInfo;
 		MMCKINFO	ckMainRIFF;
-		if (mmioDescend(MCIWavDev[index].hFile, &ckMainRIFF, NULL, 0) != 0) {
+		if (mmioDescend(MCIWavDev[wDevID].hFile, &ckMainRIFF, NULL, 0) != 0) {
 			return MCIERR_INTERNAL;
 			}
 		dprintf_mciwave(stddeb,
@@ -181,19 +182,19 @@
 			return MCIERR_INTERNAL;
 			}
 		mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
-		if (mmioDescend(MCIWavDev[index].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0) {
+		if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0) {
 			return MCIERR_INTERNAL;
 			}
 		dprintf_mciwave(stddeb,
 				"WAVE_mciOpen // Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
 				(LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType,
 				mmckInfo.cksize);
-		if (mmioRead(MCIWavDev[index].hFile, (HPSTR) lpWaveFormat,
+		if (mmioRead(MCIWavDev[wDevID].hFile, (HPSTR) lpWaveFormat,
 		    (long) sizeof(PCMWAVEFORMAT)) != (long) sizeof(PCMWAVEFORMAT)) {
 			return MCIERR_INTERNAL;
 			}
 		mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
-		if (mmioDescend(MCIWavDev[index].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0) {
+		if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0) {
 			return MCIERR_INTERNAL;
 			}
 		dprintf_mciwave(stddeb,
@@ -205,39 +206,107 @@
 			lpWaveFormat->wf.nChannels, lpWaveFormat->wf.nSamplesPerSec);
 		lpWaveFormat->wBitsPerSample = 0;
 		}
+
 	lpWaveFormat->wf.nAvgBytesPerSec = 
 		lpWaveFormat->wf.nSamplesPerSec * lpWaveFormat->wf.nBlockAlign;
 	hFormat = USER_HEAP_ALLOC(sizeof(PCMWAVEFORMAT));
-	lpDesc->lpFormat = (LPWAVEFORMAT) USER_HEAP_LIN_ADDR(hFormat);
-	memcpy(lpDesc->lpFormat, lpWaveFormat, sizeof(PCMWAVEFORMAT));
+	lpFormat =  (LPWAVEFORMAT) USER_HEAP_LIN_ADDR(hFormat);
+	memcpy(lpFormat, lpWaveFormat, sizeof(PCMWAVEFORMAT));
+	lpDesc->lpFormat = (LPWAVEFORMAT)USER_HEAP_SEG_ADDR(hFormat);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_SEG_ADDR(hDesc);
-	dwRet = wodMessage(index, WODM_OPEN, 0, (DWORD)lpDesc, CALLBACK_NULL);
-	dwRet = widMessage(index, WIDM_OPEN, 0, (DWORD)lpDesc, CALLBACK_NULL);
+
+/*
+   By default the device will be opened for output, the MCI_CUE function is there to
+   change from output to input and back
+*/
+
+	dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)lpDesc, CALLBACK_NULL);
+
 	USER_HEAP_FREE(hFormat);
 	USER_HEAP_FREE(hDesc);
 	return 0;
 }
 
 /**************************************************************************
+*                               WAVE_mciCue             [internal]
+*/
+
+static DWORD WAVE_mciCue(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
+{
+/*
+   FIXME
+
+   This routine is far from complete. At the moment only a check is done on the
+   MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
+   is the default.
+
+   The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT are
+   ignored
+*/
+
+        DWORD          dwRet;
+        HLOCAL16       hDesc;
+        LPWAVEOPENDESC lpDesc;
+
+	dprintf_mciwave(stddeb,"WAVE_mciCue(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
+
+/* always close elements ? */
+
+	if (MCIWavDev[wDevID].hFile != 0) {
+	  mmioClose(MCIWavDev[wDevID].hFile, 0);
+	  MCIWavDev[wDevID].hFile = 0;
+	}
+
+	hDesc = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
+	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hDesc);
+
+	dwRet = MMSYSERR_NOERROR;  /* assume success */
+
+	if ((dwParam & MCI_WAVE_INPUT) && !MCIWavDev[wDevID].fInput) {
+
+/* FIXME this is just a hack WOutDev should be hidden here */
+	        memcpy(lpDesc,&WOutDev[wDevID].waveDesc,sizeof(WAVEOPENDESC));
+
+	        dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
+	        if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
+	        dwRet = widMessage(wDevID, WIDM_OPEN, 0, (DWORD)lpDesc, CALLBACK_NULL);
+	}
+	else if (MCIWavDev[wDevID].fInput) {
+/* FIXME this is just a hack WInDev should be hidden here */
+	        memcpy(lpDesc,&WInDev[wDevID].waveDesc,sizeof(WAVEOPENDESC));
+
+	        dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
+	        if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
+	        dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)lpDesc, CALLBACK_NULL);
+	}
+
+	USER_HEAP_FREE(hDesc);
+
+        return dwRet;
+}
+
+/**************************************************************************
 * 				WAVE_mciClose		[internal]
 */
 static DWORD WAVE_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
 {
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	DWORD		dwRet;
+
 	dprintf_mciwave(stddeb,
-		"WAVE_mciClose(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
-	MCIWavDev[index].nUseCount--;
-	if (MCIWavDev[index].nUseCount == 0) {
-		if (MCIWavDev[index].hFile != 0) {
-			mmioClose(MCIWavDev[index].hFile, 0);
-			MCIWavDev[index].hFile = 0;
-			}
-		dwRet = wodMessage(index, WODM_CLOSE, 0, 0L, 0L);
-		if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
-		dwRet = widMessage(index, WIDM_CLOSE, 0, 0L, 0L);
-		if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
+			"WAVE_mciClose(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
+	MCIWavDev[wDevID].nUseCount--;
+	if (MCIWavDev[wDevID].nUseCount == 0) {
+	        if (MCIWavDev[wDevID].hFile != 0) {
+		        mmioClose(MCIWavDev[wDevID].hFile, 0);
+			MCIWavDev[wDevID].hFile = 0;
 		}
+		if (MCIWavDev[wDevID].fInput)
+		        dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
+		else
+		        dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
+	  
+		if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
+	}
 	return 0;
 }
 
@@ -247,7 +316,6 @@
 */
 static DWORD WAVE_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
 {
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	int				start, end;
 	LONG			bufsize, count;
 	HGLOBAL16		hData;
@@ -255,13 +323,20 @@
 	LPWAVEHDR		lpWaveHdr;
 	LPWAVEHDR		lp16WaveHdr;
 	DWORD			dwRet;
+
 	dprintf_mciwave(stddeb,
 		 "WAVE_mciPlay(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-	if (MCIWavDev[index].hFile == 0) {
-        dprintf_mciwave(stddeb,"WAVE_mciPlay // can't find file='%08lx' !\n",
-                        MCIWavDev[index].openParms.lpstrElementName);
+
+	if (MCIWavDev[wDevID].fInput) {
+	        dprintf_mciwave(stddeb,"WAVE_mciPlay // cannot play on input device\n");
+		return MCIERR_NONAPPLICABLE_FUNCTION;
+	}
+
+	if (MCIWavDev[wDevID].hFile == 0) {
+                dprintf_mciwave(stddeb,"WAVE_mciPlay // can't find file='%08lx' !\n",
+                        MCIWavDev[wDevID].openParms.lpstrElementName);
 		return MCIERR_FILE_NOT_FOUND;
-		}
+	}
 	start = 1; 		end = 99999;
 	if (dwFlags & MCI_FROM) {
 		start = lpParms->dwFrom; 
@@ -290,7 +365,7 @@
 		}
 #endif
 	bufsize = 64000;
-	lpWaveHdr = &MCIWavDev[index].WaveHdr;
+	lpWaveHdr = &MCIWavDev[wDevID].WaveHdr;
 	hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
 	lpWaveHdr->lpData = (LPSTR) WIN16_GlobalLock16(hData);
 	lpWaveHdr->dwUser = 0L;
@@ -300,9 +375,9 @@
 	lp16WaveHdr = (LPWAVEHDR) USER_HEAP_SEG_ADDR(hWaveHdr);
 	memcpy(PTR_SEG_TO_LIN(lp16WaveHdr), lpWaveHdr, sizeof(WAVEHDR));
 	lpWaveHdr = PTR_SEG_TO_LIN(lp16WaveHdr);
-	dwRet = wodMessage(index, WODM_PREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
+	dwRet = wodMessage(wDevID, WODM_PREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
 	while(TRUE) {
-		count = mmioRead(MCIWavDev[index].hFile, 
+		count = mmioRead(MCIWavDev[wDevID].hFile, 
 			PTR_SEG_TO_LIN(lpWaveHdr->lpData), bufsize);
 		dprintf_mciwave(stddeb,"WAVE_mciPlay // mmioRead bufsize=%ld count=%ld\n", bufsize, count);
 		if (count < 1) break;
@@ -310,9 +385,9 @@
 /*		lpWaveHdr->dwBytesRecorded = count; */
 		dprintf_mciwave(stddeb,"WAVE_mciPlay // before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
 				lpWaveHdr, lpWaveHdr->dwBufferLength, lpWaveHdr->dwBytesRecorded);
-		dwRet = wodMessage(index, WODM_WRITE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
+		dwRet = wodMessage(wDevID, WODM_WRITE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
 		}
-	dwRet = wodMessage(index, WODM_UNPREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
+	dwRet = wodMessage(wDevID, WODM_UNPREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
 	if (lpWaveHdr->lpData != NULL) {
 		GlobalUnlock16(hData);
 		GlobalFree16(hData);
@@ -322,7 +397,7 @@
 	if (dwFlags & MCI_NOTIFY) {
 		dprintf_mciwave(stddeb,"WAVE_mciPlay // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			MCIWavDev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
 	return 0;
 }
@@ -333,8 +408,7 @@
 */
 static DWORD WAVE_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
 {
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
-	int				start, end;
+	int		       	start, end;
 	LONG			bufsize;
 	HGLOBAL16		hData;
 	HLOCAL16		hWaveHdr;
@@ -344,11 +418,17 @@
 
 	dprintf_mciwave(stddeb,
 		"WAVE_mciRecord(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-	if (MCIWavDev[index].hFile == 0) {
+
+	if (!MCIWavDev[wDevID].fInput) {
+	        dprintf_mciwave(stddeb,"WAVE_mciPlay // cannot record on output device\n");
+		return MCIERR_NONAPPLICABLE_FUNCTION;
+	}
+
+	if (MCIWavDev[wDevID].hFile == 0) {
 		dprintf_mciwave(stddeb,"WAVE_mciRecord // can't find file='%08lx' !\n", 
-				MCIWavDev[index].openParms.lpstrElementName);
+				MCIWavDev[wDevID].openParms.lpstrElementName);
 		return MCIERR_FILE_NOT_FOUND;
-		}
+	}
 	start = 1; 		end = 99999;
 	if (dwFlags & MCI_FROM) {
 		start = lpParms->dwFrom; 
@@ -360,7 +440,7 @@
 		dprintf_mciwave(stddeb,"WAVE_mciRecord // MCI_TO=%d \n", end);
 		}
 	bufsize = 64000;
-	lpWaveHdr = &MCIWavDev[index].WaveHdr;
+	lpWaveHdr = &MCIWavDev[wDevID].WaveHdr;
 	hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
 	lpWaveHdr->lpData = (LPSTR) WIN16_GlobalLock16(hData);
 	lpWaveHdr->dwBufferLength = bufsize;
@@ -371,18 +451,18 @@
 	lp16WaveHdr = (LPWAVEHDR) USER_HEAP_SEG_ADDR(hWaveHdr);
 	memcpy(PTR_SEG_TO_LIN(lp16WaveHdr), lpWaveHdr, sizeof(WAVEHDR));
 	lpWaveHdr = PTR_SEG_TO_LIN(lp16WaveHdr);
-	dwRet = widMessage(index, WIDM_PREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
+	dwRet = widMessage(wDevID, WIDM_PREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
     dprintf_mciwave(stddeb,"WAVE_mciRecord // after WIDM_PREPARE \n");
 	while(TRUE) {
 		lpWaveHdr->dwBytesRecorded = 0;
-		dwRet = widMessage(index, WIDM_START, 0, 0L, 0L);
+		dwRet = widMessage(wDevID, WIDM_START, 0, 0L, 0L);
 		dprintf_mciwave(stddeb,
                     "WAVE_mciRecord // after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
 					lpWaveHdr, lpWaveHdr->dwBytesRecorded);
 		if (lpWaveHdr->dwBytesRecorded == 0) break;
 		}
 	dprintf_mciwave(stddeb,"WAVE_mciRecord // before WIDM_UNPREPARE \n");
-	dwRet = widMessage(index, WIDM_UNPREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
+	dwRet = widMessage(wDevID, WIDM_UNPREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
 	dprintf_mciwave(stddeb,"WAVE_mciRecord // after WIDM_UNPREPARE \n");
 	if (lpWaveHdr->lpData != NULL) {
 		GlobalUnlock16(hData);
@@ -393,7 +473,7 @@
 	if (dwFlags & MCI_NOTIFY) {
 	  dprintf_mciwave(stddeb,"WAVE_mciRecord // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			MCIWavDev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
 	return 0;
 }
@@ -509,7 +589,6 @@
 */
 static DWORD WAVE_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
 {
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_mciwave(stddeb,
 		"WAVE_mciStatus(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
@@ -597,7 +676,7 @@
 	if (dwFlags & MCI_NOTIFY) {
 		dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			MCIWavDev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
  	return 0;
 }
@@ -658,7 +737,6 @@
 */
 static DWORD WAVE_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS lpParms)
 {
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_mciwave(stddeb,
 		"WAVE_mciInfo(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
@@ -669,7 +747,7 @@
 			break;
 		case MCI_INFO_FILE:
 			lpParms->lpstrReturn = 
-				(LPSTR)MCIWavDev[index].openParms.lpstrElementName;
+				(LPSTR)MCIWavDev[wDevID].openParms.lpstrElementName;
 			break;
 		case MCI_WAVE_INPUT:
 			lpParms->lpstrReturn = "Linux Sound System 0.5";
@@ -704,8 +782,9 @@
 	dprintf_mciwave(stddeb,
 		   "wodGetDevCaps(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
 	if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
+	if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
 	audio = open (SOUND_DEV, O_WRONLY, 0);
-	if (audio == -1) return MMSYSERR_NOTENABLED;
+	if (audio == -1) return MMSYSERR_ALLOCATED ;
 #ifdef EMULATE_SB16
 	lpCaps->wMid = 0x0002;
 	lpCaps->wPid = 0x0104;
@@ -777,10 +856,11 @@
 		return MMSYSERR_ALLOCATED;
 		}
 	WOutDev[wDevID].unixdev = 0;
+	if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
 	audio = open (SOUND_DEV, O_WRONLY, 0);
 	if (audio == -1) {
 		dprintf_mciwave(stddeb,"Linux 'wodOpen' // can't open !\n");
-		return MMSYSERR_NOTENABLED;
+		return MMSYSERR_ALLOCATED ;
 		}
 	IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
 	if (abuf_size < 1024 || abuf_size > 65536) {
@@ -810,7 +890,10 @@
 	WOutDev[wDevID].dwTotalPlayed = 0;
 	WOutDev[wDevID].bufsize = abuf_size;
 	memcpy(&WOutDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
+	dprintf_mciwave(stddeb,"Linux 'wodOpen' // lpDesc->lpFormat = %p\n",lpDesc->lpFormat);
         lpFormat = (LPWAVEFORMAT) PTR_SEG_TO_LIN(lpDesc->lpFormat); 
+/*	lpFormat = lpDesc->lpFormat; */
+	dprintf_mciwave(stddeb,"Linux 'wodOpen' // lpFormat = %p\n",lpFormat);
 	if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
 		dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad format %04X !\n",
 				lpFormat->wFormatTag);
@@ -1042,7 +1125,7 @@
 	int		volume, left, right;
 	dprintf_mciwave(stddeb,"wodGetVolume(%u, %p);\n", wDevID, lpdwVol);
 	if (lpdwVol == NULL) return MMSYSERR_NOTENABLED;
-	if ((mixer = open("/dev/mixer", O_RDONLY)) < 0) {
+	if ((mixer = open(MIXER_DEV, O_RDONLY)) < 0) {
 		dprintf_mciwave(stddeb, "Linux 'wodGetVolume' // mixer device not available !\n");
 		return MMSYSERR_NOTENABLED;
 		}
@@ -1053,7 +1136,7 @@
 	close(mixer);
 	left = volume & 0x7F;
 	right = (volume >> 8) & 0x7F;
-	printf("Linux 'AUX_GetVolume' // left=%d right=%d !\n", left, right);
+	dprintf_mciwave(stddeb,"Linux 'wodGetVolume' // left=%d right=%d !\n", left, right);
 	*lpdwVol = MAKELONG(left << 9, right << 9);
 	return MMSYSERR_NOERROR;
 }
@@ -1069,7 +1152,7 @@
 	dprintf_mciwave(stddeb,"wodSetVolume(%u, %08lX);\n", wDevID, dwParam);
 	volume = (LOWORD(dwParam) >> 9 & 0x7F) + 
 		((HIWORD(dwParam) >> 9  & 0x7F) << 8);
-	if ((mixer = open("/dev/mixer", O_WRONLY)) < 0) {
+	if ((mixer = open(MIXER_DEV, O_WRONLY)) < 0) {
 		dprintf_mciwave(stddeb,	"Linux 'wodSetVolume' // mixer device not available !\n");
 		return MMSYSERR_NOTENABLED;
 		}
@@ -1114,13 +1197,13 @@
 		case WODM_GETNUMDEVS:
 			return 1L;
 		case WODM_GETPITCH:
-			return 0L;
+			return MMSYSERR_NOTSUPPORTED;
 		case WODM_SETPITCH:
-			return 0L;
+			return MMSYSERR_NOTSUPPORTED;
 		case WODM_GETPLAYBACKRATE:
-			return 0L;
+			return MMSYSERR_NOTSUPPORTED;
 		case WODM_SETPLAYBACKRATE:
-			return 0L;
+			return MMSYSERR_NOTSUPPORTED;
 		case WODM_GETVOLUME:
 			return wodGetVolume(wDevID, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
 		case WODM_SETVOLUME:
@@ -1156,12 +1239,13 @@
 	dprintf_mciwave(stddeb,
 		"widGetDevCaps(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
 	if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
+	if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
 	audio = open (SOUND_DEV, O_RDONLY, 0);
-	if (audio == -1) return MMSYSERR_NOTENABLED;
+	if (audio == -1) return MMSYSERR_ALLOCATED ;
 #ifdef EMULATE_SB16
 	lpCaps->wMid = 0x0002;
 	lpCaps->wPid = 0x0004;
-	strcpy(lpCaps->szPname, "SB16 Wave Out");
+	strcpy(lpCaps->szPname, "SB16 Wave In");
 #else
 	lpCaps->wMid = 0x00FF; 	/* Manufac ID */
 	lpCaps->wPid = 0x0001; 	/* Product ID */
@@ -1225,10 +1309,11 @@
 		return MMSYSERR_ALLOCATED;
 		}
 	WInDev[wDevID].unixdev = 0;
+	if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
 	audio = open (SOUND_DEV, O_RDONLY, 0);
 	if (audio == -1) {
 		dprintf_mciwave(stddeb,"Linux 'widOpen' // can't open !\n");
-		return MMSYSERR_NOTENABLED;
+		return MMSYSERR_ALLOCATED;
 		}
 	IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
 	if (abuf_size < 1024 || abuf_size > 65536) {
@@ -1258,7 +1343,8 @@
 	WInDev[wDevID].bufsize = abuf_size;
 	WInDev[wDevID].dwTotalRecorded = 0;
 	memcpy(&WInDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
-        lpFormat = lpDesc->lpFormat;
+        lpFormat = (LPWAVEFORMAT) PTR_SEG_TO_LIN(lpDesc->lpFormat); 
+/*        lpFormat = lpDesc->lpFormat; */
 	if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
 		dprintf_mciwave(stddeb,"Linux 'widOpen' // Bad format %04X !\n",
 					lpFormat->wFormatTag);
@@ -1619,6 +1705,8 @@
 		case MCI_OPEN_DRIVER:
 		case MCI_OPEN:
 			return WAVE_mciOpen(dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMS)PTR_SEG_TO_LIN(dwParam2));
+		case MCI_CUE:
+			return WAVE_mciCue(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
 		case MCI_CLOSE_DRIVER:
 		case MCI_CLOSE:
 			return WAVE_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
diff --git a/multimedia/mcianim.c b/multimedia/mcianim.c
index babcf25..6ab5ddf 100644
--- a/multimedia/mcianim.c
+++ b/multimedia/mcianim.c
@@ -17,8 +17,6 @@
 #include "stddebug.h"
 #include "debug.h"
 
-int MMSYSTEM_DevIDToIndex(UINT16);
-
 #define MAX_ANIMDRV 		2
 
 #define ANIMFRAMES_PERSEC 	30
@@ -54,24 +52,24 @@
 static DWORD ANIM_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_OPEN_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	LPSTR		lpstrElementName;
 	char		str[128];
+
 	dprintf_mcianim(stddeb,"ANIM_mciOpen(%04X, %08lX, %p);\n", 
 					wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
-	if (AnimDev[index].nUseCount > 0) {
+	if (AnimDev[wDevID].nUseCount > 0) {
 		/* The driver already open on this channel */
 		/* If the driver was opened shareable before and this open specifies */
 		/* shareable then increment the use count */
-		if (AnimDev[index].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
-			++AnimDev[index].nUseCount;
+		if (AnimDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
+			++AnimDev[wDevID].nUseCount;
 		else
 			return MCIERR_MUST_USE_SHAREABLE;
 		}
 	else {
-		AnimDev[index].nUseCount = 1;
-		AnimDev[index].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
+		AnimDev[wDevID].nUseCount = 1;
+		AnimDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
 		}
 	dprintf_mcianim(stddeb,"ANIM_mciOpen // wDevID=%04X\n", wDevID);
 	lpParms->wDeviceID = wDevID;
@@ -85,21 +83,21 @@
 			CharUpper32A(str);
 			}
 		}
-	memcpy(&AnimDev[index].openParms, lpParms, sizeof(MCI_OPEN_PARMS));
-	AnimDev[index].wNotifyDeviceID = lpParms->wDeviceID;
-	AnimDev[index].mode = 0;
-	AnimDev[index].dwTimeFormat = MCI_FORMAT_TMSF;
-	AnimDev[index].nCurTrack = 0;
-	AnimDev[index].nTracks = 0;
-	AnimDev[index].dwTotalLen = 0;
-	AnimDev[index].lpdwTrackLen = NULL;
-	AnimDev[index].lpdwTrackPos = NULL;
+	memcpy(&AnimDev[wDevID].openParms, lpParms, sizeof(MCI_OPEN_PARMS));
+	AnimDev[wDevID].wNotifyDeviceID = lpParms->wDeviceID;
+	AnimDev[wDevID].mode = 0;
+	AnimDev[wDevID].dwTimeFormat = MCI_FORMAT_TMSF;
+	AnimDev[wDevID].nCurTrack = 0;
+	AnimDev[wDevID].nTracks = 0;
+	AnimDev[wDevID].dwTotalLen = 0;
+	AnimDev[wDevID].lpdwTrackLen = NULL;
+	AnimDev[wDevID].lpdwTrackPos = NULL;
 	if (dwFlags & MCI_NOTIFY) {
 		dprintf_mcianim(stddeb,
 			"ANIM_mciOpen // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			AnimDev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
  	return 0;
 #else
@@ -113,11 +111,10 @@
 static DWORD ANIM_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_mcianim(stddeb,"ANIM_mciClose(%u, %08lX, %p);\n", 
 				wDevID, dwParam, lpParms);
-	if (AnimDev[index].lpdwTrackLen != NULL) free(AnimDev[index].lpdwTrackLen);
-	if (AnimDev[index].lpdwTrackPos != NULL) free(AnimDev[index].lpdwTrackPos);
+	if (AnimDev[wDevID].lpdwTrackLen != NULL) free(AnimDev[wDevID].lpdwTrackLen);
+	if (AnimDev[wDevID].lpdwTrackPos != NULL) free(AnimDev[wDevID].lpdwTrackPos);
 #endif
         return 0;
 }
@@ -185,7 +182,6 @@
 {
 	DWORD	dwTime = 0;
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	UINT16	wTrack;
 	UINT16	wMinutes;
 	UINT16	wSeconds;
@@ -212,11 +208,11 @@
 			/* unknown format ! force TMSF ! ... */
 			dwFormatType = MCI_FORMAT_TMSF;
 		case MCI_FORMAT_TMSF:
-			for (wTrack = 0; wTrack < AnimDev[index].nTracks; wTrack++) {
-/*				dwTime += AnimDev[index].lpdwTrackLen[wTrack - 1];
+			for (wTrack = 0; wTrack < AnimDev[wDevID].nTracks; wTrack++) {
+/*				dwTime += AnimDev[wDevID].lpdwTrackLen[wTrack - 1];
 				printf("Adding trk#%u curpos=%u \n", dwTime);
 				if (dwTime >= dwFrame) break; */
-				if (AnimDev[index].lpdwTrackPos[wTrack - 1] >= dwFrame) break;
+				if (AnimDev[wDevID].lpdwTrackPos[wTrack - 1] >= dwFrame) break;
 				}
 			wMinutes = dwFrame / ANIMFRAMES_PERMIN;
 			wSeconds = (dwFrame - ANIMFRAMES_PERMIN * wMinutes) / ANIMFRAMES_PERSEC;
@@ -240,7 +236,6 @@
 {
 	DWORD	dwFrame = 0;
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	UINT16	wTrack;
 	dprintf_mcianim(stddeb,"ANIM_CalcFrame(%u, %08lX, %lu);\n", 
 			wDevID, dwFormatType, dwTime);
@@ -271,8 +266,8 @@
 				MCI_TMSF_SECOND(dwTime), MCI_TMSF_FRAME(dwTime));
 			dprintf_mcianim(stddeb,
 				"ANIM_CalcFrame // TMSF trackpos[%u]=%lu\n",
-				wTrack, AnimDev[index].lpdwTrackPos[wTrack - 1]);
-			dwFrame = AnimDev[index].lpdwTrackPos[wTrack - 1];
+				wTrack, AnimDev[wDevID].lpdwTrackPos[wTrack - 1]);
+			dwFrame = AnimDev[wDevID].lpdwTrackPos[wTrack - 1];
 			dwFrame += ANIMFRAMES_PERMIN * MCI_TMSF_MINUTE(dwTime);
 			dwFrame += ANIMFRAMES_PERSEC * MCI_TMSF_SECOND(dwTime);
 			dwFrame += MCI_TMSF_FRAME(dwTime);
@@ -289,7 +284,6 @@
 static DWORD ANIM_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_mcianim(stddeb,"ANIM_mciInfo(%u, %08lX, %p);\n", 
 		wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
@@ -300,7 +294,7 @@
 			break;
 		case MCI_INFO_FILE:
 			lpParms->lpstrReturn = 
-				(LPSTR)AnimDev[index].openParms.lpstrElementName;
+				(LPSTR)AnimDev[wDevID].openParms.lpstrElementName;
 			break;
 		case MCI_ANIM_INFO_TEXT:
 			lpParms->lpstrReturn = "Animation Window";
@@ -324,7 +318,6 @@
 static DWORD ANIM_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_mcianim(stddeb,"ANIM_mciStatus(%u, %08lX, %p);\n", 
 			wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
@@ -333,30 +326,30 @@
 			"ANIM_mciStatus // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			AnimDev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
 	if (dwFlags & MCI_STATUS_ITEM) {
 		switch(lpParms->dwItem) {
 			case MCI_STATUS_CURRENT_TRACK:
-				lpParms->dwReturn = AnimDev[index].nCurTrack;
+				lpParms->dwReturn = AnimDev[wDevID].nCurTrack;
 				dprintf_mcianim(stddeb,"ANIM_mciStatus // CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
 			 	return 0;
 			case MCI_STATUS_LENGTH:
 				if (dwFlags & MCI_TRACK) {
 					dprintf_mcianim(stddeb,"ANIM_mciStatus // MCI_TRACK #%lu LENGTH=??? !\n",
 														lpParms->dwTrack);
-					if (lpParms->dwTrack > AnimDev[index].nTracks)
+					if (lpParms->dwTrack > AnimDev[wDevID].nTracks)
 						return MCIERR_OUTOFRANGE;
-					lpParms->dwReturn = AnimDev[index].lpdwTrackLen[lpParms->dwTrack];
+					lpParms->dwReturn = AnimDev[wDevID].lpdwTrackLen[lpParms->dwTrack];
 					}
 				else
-					lpParms->dwReturn = AnimDev[index].dwTotalLen;
+					lpParms->dwReturn = AnimDev[wDevID].dwTotalLen;
 				lpParms->dwReturn = ANIM_CalcTime(wDevID, 
-					AnimDev[index].dwTimeFormat, lpParms->dwReturn);
+					AnimDev[wDevID].dwTimeFormat, lpParms->dwReturn);
                 		dprintf_mcianim(stddeb,"ANIM_mciStatus // LENGTH=%lu !\n", lpParms->dwReturn);
 			 	return 0;
 			case MCI_STATUS_MODE:
-				lpParms->dwReturn = AnimDev[index].mode;
+				lpParms->dwReturn = AnimDev[wDevID].mode;
 				dprintf_mcianim(stddeb,"ANIM_mciStatus // MCI_STATUS_MODE=%08lX !\n",
 												lpParms->dwReturn);
 			 	return 0;
@@ -371,19 +364,19 @@
 				if (lpParms->dwReturn == (WORD)-1) return MCIERR_INTERNAL;
 			 	return 0;
 			case MCI_STATUS_POSITION:
-				lpParms->dwReturn = AnimDev[index].dwCurFrame;
+				lpParms->dwReturn = AnimDev[wDevID].dwCurFrame;
 				if (dwFlags & MCI_STATUS_START) {
 					lpParms->dwReturn = 0;
 					dprintf_mcianim(stddeb,"CDAUDIO_mciStatus // get MCI_STATUS_START !\n");
 					}
 				if (dwFlags & MCI_TRACK) {
-					if (lpParms->dwTrack > AnimDev[index].nTracks)
+					if (lpParms->dwTrack > AnimDev[wDevID].nTracks)
 						return MCIERR_OUTOFRANGE;
-					lpParms->dwReturn = AnimDev[index].lpdwTrackPos[lpParms->dwTrack - 1];
+					lpParms->dwReturn = AnimDev[wDevID].lpdwTrackPos[lpParms->dwTrack - 1];
 					dprintf_mcianim(stddeb,"ANIM_mciStatus // get MCI_TRACK #%lu !\n", lpParms->dwTrack);
 					}
 				lpParms->dwReturn = ANIM_CalcTime(wDevID, 
-					AnimDev[index].dwTimeFormat, lpParms->dwReturn);
+					AnimDev[wDevID].dwTimeFormat, lpParms->dwReturn);
 					dprintf_mcianim(stddeb,"ANIM_mciStatus // MCI_STATUS_POSITION=%08lX !\n",
 														lpParms->dwReturn);
 			 	return 0;
@@ -414,33 +407,32 @@
 static DWORD ANIM_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	int 	start, end;
 	dprintf_mcianim(stddeb,"ANIM_mciPlay(%u, %08lX, %p);\n", 
 		wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
-	start = 0; 		end = AnimDev[index].dwTotalLen;
-	AnimDev[index].nCurTrack = 1;
+	start = 0; 		end = AnimDev[wDevID].dwTotalLen;
+	AnimDev[wDevID].nCurTrack = 1;
 	if (dwFlags & MCI_FROM) {
 		start = ANIM_CalcFrame(wDevID, 
-			AnimDev[index].dwTimeFormat, lpParms->dwFrom); 
+			AnimDev[wDevID].dwTimeFormat, lpParms->dwFrom); 
         dprintf_mcianim(stddeb,"ANIM_mciPlay // MCI_FROM=%08lX -> %u \n",
 				lpParms->dwFrom, start);
 		}
 	if (dwFlags & MCI_TO) {
 		end = ANIM_CalcFrame(wDevID, 
-			AnimDev[index].dwTimeFormat, lpParms->dwTo);
+			AnimDev[wDevID].dwTimeFormat, lpParms->dwTo);
         	dprintf_mcianim(stddeb,
 			"ANIM_mciPlay // MCI_TO=%08lX -> %u \n",
 			lpParms->dwTo, end);
 		}
-	AnimDev[index].mode = MCI_MODE_PLAY;
+	AnimDev[wDevID].mode = MCI_MODE_PLAY;
 	if (dwFlags & MCI_NOTIFY) {
 		dprintf_mcianim(stddeb,
 			"ANIM_mciPlay // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			AnimDev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
 	return 0;
 #else
@@ -454,17 +446,16 @@
 static DWORD ANIM_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_mcianim(stddeb,"ANIM_mciStop(%u, %08lX, %p);\n", 
 			wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
-	AnimDev[index].mode = MCI_MODE_STOP;
+	AnimDev[wDevID].mode = MCI_MODE_STOP;
 	if (dwFlags & MCI_NOTIFY) {
 		dprintf_mcianim(stddeb,
 			"ANIM_mciStop // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			AnimDev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
  	return 0;
 #else
@@ -478,17 +469,16 @@
 static DWORD ANIM_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_mcianim(stddeb,"ANIM_mciPause(%u, %08lX, %p);\n", 
 		wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
-	AnimDev[index].mode = MCI_MODE_PAUSE;
+	AnimDev[wDevID].mode = MCI_MODE_PAUSE;
 	if (dwFlags & MCI_NOTIFY) {
 		dprintf_mcianim(stddeb,
 			"ANIM_mciPause // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			AnimDev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
 	return 0;
 #else
@@ -502,17 +492,16 @@
 static DWORD ANIM_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_mcianim(stddeb,"ANIM_mciResume(%u, %08lX, %p);\n", 
 		wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
-	AnimDev[index].mode = MCI_MODE_STOP;
+	AnimDev[wDevID].mode = MCI_MODE_STOP;
 	if (dwFlags & MCI_NOTIFY) {
 		dprintf_mcianim(stddeb,
 			"ANIM_mciResume // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			AnimDev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
 	return 0;
 #else
@@ -526,19 +515,18 @@
 static DWORD ANIM_mciSeek(UINT16 wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	DWORD	dwRet;
 	MCI_PLAY_PARMS PlayParms;
 	dprintf_mcianim(stddeb,"ANIM_mciSeek(%u, %08lX, %p);\n", 
 		wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
-	AnimDev[index].mode = MCI_MODE_SEEK;
+	AnimDev[wDevID].mode = MCI_MODE_SEEK;
 	switch(dwFlags) {
 		case MCI_SEEK_TO_START:
 			PlayParms.dwFrom = 0;
 			break;
 		case MCI_SEEK_TO_END:
-			PlayParms.dwFrom = AnimDev[index].dwTotalLen;
+			PlayParms.dwFrom = AnimDev[wDevID].dwTotalLen;
 			break;
 		case MCI_TO:
 			PlayParms.dwFrom = lpParms->dwTo;
@@ -552,7 +540,7 @@
 			"ANIM_mciSeek // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			AnimDev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
 	return dwRet;
 #else
@@ -567,7 +555,6 @@
 static DWORD ANIM_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_mcianim(stddeb,"ANIM_mciSet(%u, %08lX, %p);\n", 
 		wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
@@ -591,7 +578,7 @@
 				fprintf(stderr,"ANIM_mciSet // bad time format !\n");
 				return MCIERR_BAD_TIME_FORMAT;
 			}
-		AnimDev[index].dwTimeFormat = lpParms->dwTimeFormat;
+		AnimDev[wDevID].dwTimeFormat = lpParms->dwTimeFormat;
 		}
 	if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
 	if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
@@ -601,7 +588,7 @@
 			"ANIM_mciSet // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			AnimDev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			AnimDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
 	return 0;
 #else
diff --git a/multimedia/mcicda.c b/multimedia/mcicda.c
index 5c9781d..4213933 100644
--- a/multimedia/mcicda.c
+++ b/multimedia/mcicda.c
@@ -25,8 +25,6 @@
 #include <sys/cdio.h>
 #endif
 
-int MMSYSTEM_DevIDToIndex(UINT16);
-
 #define SOUND_DEV "/dev/dsp"
 #ifdef __FreeBSD__
 #define CDAUDIO_DEV "/dev/rcd0c"
@@ -40,7 +38,7 @@
 #define IOCTL(a,b,c)		(c = ioctl(a,b,c) )
 #endif
 
-#define MAX_CDAUDIODRV 		2
+#define MAX_CDAUDIODRV 		(1)
 #define MAX_CDAUDIO_TRACKS 	256
 
 #define CDFRAMES_PERSEC 	75
@@ -84,14 +82,14 @@
 static UINT16 CDAUDIO_GetNumberOfTracks(UINT16 wDevID)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 #ifdef linux
 	struct cdrom_tochdr	hdr;
 #elif __FreeBSD__
 	struct ioc_toc_header	hdr;
 #endif
-	if (CDADev[index].nTracks == 0) {
-		if (ioctl(CDADev[index].unixdev,
+
+	if (CDADev[wDevID].nTracks == 0) {
+		if (ioctl(CDADev[wDevID].unixdev,
 #ifdef linux
 			  CDROMREADTOCHDR
 #elif __FreeBSD__
@@ -104,12 +102,12 @@
 			return (WORD)-1;
 			}
 #ifdef linux
-		CDADev[index].nTracks = hdr.cdth_trk1;
+		CDADev[wDevID].nTracks = hdr.cdth_trk1;
 #elif __FreeBSD__
-		CDADev[index].nTracks = hdr.ending_track - hdr.starting_track + 1;
+		CDADev[wDevID].nTracks = hdr.ending_track - hdr.starting_track + 1;
 #endif
 		}
-	return CDADev[index].nTracks;
+	return CDADev[wDevID].nTracks;
 #else
 	return (WORD)-1;
 #endif
@@ -122,7 +120,6 @@
 static BOOL32 CDAUDIO_GetTracksInfo(UINT16 wDevID)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	int		i, length;
 	int		start, last_start = 0;
 	int		total_length = 0;
@@ -132,31 +129,32 @@
 	struct ioc_read_toc_entry	entry;
 	struct cd_toc_entry             toc_buffer;
 #endif
-	if (CDADev[index].nTracks == 0) {
+
+	if (CDADev[wDevID].nTracks == 0) {
 		if (CDAUDIO_GetNumberOfTracks(wDevID) == (WORD)-1) return FALSE;
 		}
     	dprintf_cdaudio(stddeb,"CDAUDIO_GetTracksInfo // nTracks=%u\n", 
-		CDADev[index].nTracks);
-	if (CDADev[index].lpdwTrackLen != NULL) 
-		free(CDADev[index].lpdwTrackLen);
-	CDADev[index].lpdwTrackLen = (LPDWORD)malloc(
-		(CDADev[index].nTracks + 1) * sizeof(DWORD));
-	if (CDADev[index].lpdwTrackPos != NULL) 
-		free(CDADev[index].lpdwTrackPos);
-	CDADev[index].lpdwTrackPos = (LPDWORD)malloc(
-		(CDADev[index].nTracks + 1) * sizeof(DWORD));
-	if (CDADev[index].lpdwTrackLen == NULL ||
-		CDADev[index].lpdwTrackPos == NULL) {
+		CDADev[wDevID].nTracks);
+	if (CDADev[wDevID].lpdwTrackLen != NULL) 
+		free(CDADev[wDevID].lpdwTrackLen);
+	CDADev[wDevID].lpdwTrackLen = (LPDWORD)malloc(
+		(CDADev[wDevID].nTracks + 1) * sizeof(DWORD));
+	if (CDADev[wDevID].lpdwTrackPos != NULL) 
+		free(CDADev[wDevID].lpdwTrackPos);
+	CDADev[wDevID].lpdwTrackPos = (LPDWORD)malloc(
+		(CDADev[wDevID].nTracks + 1) * sizeof(DWORD));
+	if (CDADev[wDevID].lpdwTrackLen == NULL ||
+		CDADev[wDevID].lpdwTrackPos == NULL) {
         		dprintf_cdaudio(stddeb,
 				"CDAUDIO_GetTracksInfo // error allocating track table !\n");
 		return FALSE;
 		}
-	memset(CDADev[index].lpdwTrackLen, 0, 
-		(CDADev[index].nTracks + 1) * sizeof(DWORD));
-	memset(CDADev[index].lpdwTrackPos, 0, 
-		(CDADev[index].nTracks + 1) * sizeof(DWORD));
-	for (i = 0; i <= CDADev[index].nTracks; i++) {
-		if (i == CDADev[index].nTracks)
+	memset(CDADev[wDevID].lpdwTrackLen, 0, 
+		(CDADev[wDevID].nTracks + 1) * sizeof(DWORD));
+	memset(CDADev[wDevID].lpdwTrackPos, 0, 
+		(CDADev[wDevID].nTracks + 1) * sizeof(DWORD));
+	for (i = 0; i <= CDADev[wDevID].nTracks; i++) {
+		if (i == CDADev[wDevID].nTracks)
 #ifdef linux
 			entry.cdte_track = CDROM_LEADOUT;
 #elif __FreeBSD__
@@ -177,7 +175,7 @@
 		entry.data_len = sizeof(toc_buffer);
 	        entry.data = &toc_buffer;
 #endif
-		if (ioctl(CDADev[index].unixdev, 
+		if (ioctl(CDADev[wDevID].unixdev, 
 #ifdef linux
 			  CDROMREADTOCENTRY
 #elif __FreeBSD__
@@ -199,7 +197,7 @@
 #endif
 		if (i == 0) {
 			last_start = start;
-			CDADev[index].dwFirstOffset = start;
+			CDADev[wDevID].dwFirstOffset = start;
             		dprintf_cdaudio(stddeb,
 				"CDAUDIO_GetTracksInfo // dwFirstOffset=%u\n", 
 				start);
@@ -209,17 +207,16 @@
 			last_start = start;
 			start = last_start - length;
 			total_length += length;
-			CDADev[index].lpdwTrackLen[i - 1] = length;
-			CDADev[index].lpdwTrackPos[i - 1] = start;
+			CDADev[wDevID].lpdwTrackLen[i - 1] = length;
+			CDADev[wDevID].lpdwTrackPos[i - 1] = start;
             		dprintf_cdaudio(stddeb,
 			"CDAUDIO_GetTracksInfo // track #%u start=%u len=%u\n",
 				i, start, length);
 			}
 		}
-	CDADev[index].dwTotalLen = total_length;
+	CDADev[wDevID].dwTotalLen = total_length;
     	dprintf_cdaudio(stddeb,"CDAUDIO_GetTracksInfo // total_len=%u\n", 
 		total_length);
-	fflush(stdout);
 	return TRUE;
 #else
 	return FALSE;
@@ -233,46 +230,42 @@
 static DWORD CDAUDIO_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_OPEN_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index;
     	dprintf_cdaudio(stddeb,"CDAUDIO_mciOpen(%04X, %08lX, %p);\n", 
 					wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
 
-	wDevID = lpParms->wDeviceID;
-	index = MMSYSTEM_DevIDToIndex(wDevID);
-
-	if (CDADev[index].nUseCount > 0) {
+	if (CDADev[wDevID].nUseCount > 0) {
 		/* The driver already open on this channel */
 		/* If the driver was opened shareable before and this open specifies */
 		/* shareable then increment the use count */
-		if (CDADev[index].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
-			++CDADev[index].nUseCount;
+		if (CDADev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
+			++CDADev[wDevID].nUseCount;
 		else
 			return MCIERR_MUST_USE_SHAREABLE;
 		}
 	else {
-		CDADev[index].nUseCount = 1;
-		CDADev[index].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
+		CDADev[wDevID].nUseCount = 1;
+		CDADev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
 		}
     if (dwFlags & MCI_OPEN_ELEMENT) {
 		dprintf_cdaudio(stddeb,"CDAUDIO_mciOpen // MCI_OPEN_ELEMENT !\n");
 /*		return MCIERR_NO_ELEMENT_ALLOWED; */
 		}
-	memcpy(&CDADev[index].openParms, lpParms, sizeof(MCI_OPEN_PARMS));
-	CDADev[index].wNotifyDeviceID = lpParms->wDeviceID;
-	CDADev[index].unixdev = open (CDAUDIO_DEV, O_RDONLY, 0);
-	if (CDADev[index].unixdev == -1) {
+	memcpy(&CDADev[wDevID].openParms, lpParms, sizeof(MCI_OPEN_PARMS));
+	CDADev[wDevID].wNotifyDeviceID = lpParms->wDeviceID;
+	CDADev[wDevID].unixdev = open (CDAUDIO_DEV, O_RDONLY, 0);
+	if (CDADev[wDevID].unixdev == -1) {
 		dprintf_cdaudio(stddeb,"CDAUDIO_mciOpen // can't open '%s' !\n", CDAUDIO_DEV);
 		return MCIERR_HARDWARE;
 		}
-	CDADev[index].mode = 0;
-	CDADev[index].dwTimeFormat = MCI_FORMAT_TMSF;
-	CDADev[index].nCurTrack = 0;
-	CDADev[index].nTracks = 0;
-	CDADev[index].dwTotalLen = 0;
-	CDADev[index].dwFirstOffset = 0;
-	CDADev[index].lpdwTrackLen = NULL;
-	CDADev[index].lpdwTrackPos = NULL;
+	CDADev[wDevID].mode = 0;
+	CDADev[wDevID].dwTimeFormat = MCI_FORMAT_TMSF;
+	CDADev[wDevID].nCurTrack = 0;
+	CDADev[wDevID].nTracks = 0;
+	CDADev[wDevID].dwTotalLen = 0;
+	CDADev[wDevID].dwFirstOffset = 0;
+	CDADev[wDevID].lpdwTrackLen = NULL;
+	CDADev[wDevID].lpdwTrackPos = NULL;
 	if (!CDAUDIO_GetTracksInfo(wDevID)) {
 		dprintf_cdaudio(stddeb,"CDAUDIO_mciOpen // error reading TracksInfo !\n");
 /*		return MCIERR_INTERNAL; */
@@ -282,7 +275,7 @@
 			"CDAUDIO_mciOpen // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			CDADev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
  	return 0;
 #else
@@ -296,12 +289,11 @@
 static DWORD CDAUDIO_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
     	dprintf_cdaudio(stddeb,"CDAUDIO_mciClose(%04X, %08lX, %p);\n", 
 		wDevID, dwParam, lpParms);
-	if (CDADev[index].lpdwTrackLen != NULL) free(CDADev[index].lpdwTrackLen);
-	if (CDADev[index].lpdwTrackPos != NULL) free(CDADev[index].lpdwTrackPos);
-	close(CDADev[index].unixdev);
+	if (CDADev[wDevID].lpdwTrackLen != NULL) free(CDADev[wDevID].lpdwTrackLen);
+	if (CDADev[wDevID].lpdwTrackPos != NULL) free(CDADev[wDevID].lpdwTrackPos);
+	close(CDADev[wDevID].unixdev);
 #endif
         return 0;
 }
@@ -396,7 +388,6 @@
 {
 	DWORD	dwFrame = 0;
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	UINT16	wTrack;
     
     	dprintf_cdaudio(stddeb,"CDAUDIO_CalcFrame(%04X, %08lX, %lu);\n", 
@@ -429,8 +420,8 @@
 					MCI_TMSF_SECOND(dwTime), MCI_TMSF_FRAME(dwTime));
             		dprintf_cdaudio(stddeb,
 				"CDAUDIO_CalcFrame // TMSF trackpos[%u]=%lu\n",
-				wTrack, CDADev[index].lpdwTrackPos[wTrack - 1]);
-			dwFrame = CDADev[index].lpdwTrackPos[wTrack - 1];
+				wTrack, CDADev[wDevID].lpdwTrackPos[wTrack - 1]);
+			dwFrame = CDADev[wDevID].lpdwTrackPos[wTrack - 1];
 			dwFrame += CDFRAMES_PERMIN * MCI_TMSF_MINUTE(dwTime);
 			dwFrame += CDFRAMES_PERSEC * MCI_TMSF_SECOND(dwTime);
 			dwFrame += MCI_TMSF_FRAME(dwTime);
@@ -447,35 +438,34 @@
 static BOOL32 CDAUDIO_GetCDStatus(UINT16 wDevID)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
-	int		oldmode = CDADev[index].mode;
+	int		oldmode = CDADev[wDevID].mode;
 #ifdef __FreeBSD__
 	struct ioc_read_subchannel	read_sc;
 
 	read_sc.address_format = CD_MSF_FORMAT;
 	read_sc.data_format    = CD_CURRENT_POSITION;
 	read_sc.track          = 0;
-	read_sc.data_len       = sizeof(CDADev[index].sc);
-	read_sc.data	       = (struct cd_sub_channel_info *)&CDADev[index].sc;
+	read_sc.data_len       = sizeof(CDADev[wDevID].sc);
+	read_sc.data	       = (struct cd_sub_channel_info *)&CDADev[wDevID].sc;
 #elif linux
-	CDADev[index].sc.cdsc_format = CDROM_MSF;
+	CDADev[wDevID].sc.cdsc_format = CDROM_MSF;
 #endif
-	if (ioctl(CDADev[index].unixdev,
+	if (ioctl(CDADev[wDevID].unixdev,
 #ifdef linux
-		  CDROMSUBCHNL, &CDADev[index].sc
+		  CDROMSUBCHNL, &CDADev[wDevID].sc
 #elif __FreeBSD__
 		  CDIOCREADSUBCHANNEL, &read_sc
 #endif
 		  )) {
         	dprintf_cdaudio(stddeb,"CDAUDIO_GetCDStatus // opened or no_media !\n");
-		CDADev[index].mode = MCI_MODE_NOT_READY;
+		CDADev[wDevID].mode = MCI_MODE_NOT_READY;
 		return TRUE;
 		}
 	switch (
 #ifdef linux
-		CDADev[index].sc.cdsc_audiostatus
+		CDADev[wDevID].sc.cdsc_audiostatus
 #elif __FreeBSD__
-		CDADev[index].sc.header.audio_status
+		CDADev[wDevID].sc.header.audio_status
 #endif
 		) {
 #ifdef linux
@@ -485,9 +475,9 @@
 #endif
             		dprintf_cdaudio(stddeb,"CDAUDIO_GetCDStatus // device doesn't support status, returning NOT_READY.\n");
 #ifdef linux
-			CDADev[index].mode = MCI_MODE_NOT_READY;
+			CDADev[wDevID].mode = MCI_MODE_NOT_READY;
 #elif __FreeBSD__
-			CDADev[index].mode = MCI_MODE_STOP;
+			CDADev[wDevID].mode = MCI_MODE_STOP;
 #endif
 			break;
 #ifdef linux
@@ -495,7 +485,7 @@
 #elif __FreeBSD__
 		case CD_AS_NO_STATUS:
 #endif
-			CDADev[index].mode = MCI_MODE_STOP;
+			CDADev[wDevID].mode = MCI_MODE_STOP;
             		dprintf_cdaudio(stddeb,"CDAUDIO_GetCDStatus // MCI_MODE_STOP !\n");
 			break;
 #ifdef linux
@@ -503,7 +493,7 @@
 #elif __FreeBSD__
 		case CD_AS_PLAY_IN_PROGRESS:
 #endif
-			CDADev[index].mode = MCI_MODE_PLAY;
+			CDADev[wDevID].mode = MCI_MODE_PLAY;
             		dprintf_cdaudio(stddeb,"CDAUDIO_GetCDStatus // MCI_MODE_PLAY !\n");
 			break;
 #ifdef linux
@@ -511,45 +501,45 @@
 #elif __FreeBSD__
 		case CD_AS_PLAY_PAUSED:
 #endif
-			CDADev[index].mode = MCI_MODE_PAUSE;
+			CDADev[wDevID].mode = MCI_MODE_PAUSE;
             		dprintf_cdaudio(stddeb,"CDAUDIO_GetCDStatus // MCI_MODE_PAUSE !\n");
 			break;
 		default:
             		dprintf_cdaudio(stddeb,"CDAUDIO_GetCDStatus // status=%02X !\n",
 #ifdef linux
-					CDADev[index].sc.cdsc_audiostatus
+					CDADev[wDevID].sc.cdsc_audiostatus
 #elif __FreeBSD__
-					CDADev[index].sc.header.audio_status
+					CDADev[wDevID].sc.header.audio_status
 #endif
 					);
 		}
 #ifdef linux
-	CDADev[index].nCurTrack = CDADev[index].sc.cdsc_trk;
-	CDADev[index].dwCurFrame = 
-		CDFRAMES_PERMIN * CDADev[index].sc.cdsc_absaddr.msf.minute +
-		CDFRAMES_PERSEC * CDADev[index].sc.cdsc_absaddr.msf.second +
-		CDADev[index].sc.cdsc_absaddr.msf.frame;
+	CDADev[wDevID].nCurTrack = CDADev[wDevID].sc.cdsc_trk;
+	CDADev[wDevID].dwCurFrame = 
+		CDFRAMES_PERMIN * CDADev[wDevID].sc.cdsc_absaddr.msf.minute +
+		CDFRAMES_PERSEC * CDADev[wDevID].sc.cdsc_absaddr.msf.second +
+		CDADev[wDevID].sc.cdsc_absaddr.msf.frame;
 #elif __FreeBSD__
-	CDADev[index].nCurTrack = CDADev[index].sc.what.position.track_number;
-	CDADev[index].dwCurFrame = 
-		CDFRAMES_PERMIN * CDADev[index].sc.what.position.absaddr.msf.minute +
-		CDFRAMES_PERSEC * CDADev[index].sc.what.position.absaddr.msf.second +
-		CDADev[index].sc.what.position.absaddr.msf.frame;
+	CDADev[wDevID].nCurTrack = CDADev[wDevID].sc.what.position.track_number;
+	CDADev[wDevID].dwCurFrame = 
+		CDFRAMES_PERMIN * CDADev[wDevID].sc.what.position.absaddr.msf.minute +
+		CDFRAMES_PERSEC * CDADev[wDevID].sc.what.position.absaddr.msf.second +
+		CDADev[wDevID].sc.what.position.absaddr.msf.frame;
 #endif
     	dprintf_cdaudio(stddeb,"CDAUDIO_GetCDStatus // %02u-%02u:%02u:%02u \n",
 #ifdef linux
-		CDADev[index].sc.cdsc_trk,
-		CDADev[index].sc.cdsc_absaddr.msf.minute,
-		CDADev[index].sc.cdsc_absaddr.msf.second,
-		CDADev[index].sc.cdsc_absaddr.msf.frame
+		CDADev[wDevID].sc.cdsc_trk,
+		CDADev[wDevID].sc.cdsc_absaddr.msf.minute,
+		CDADev[wDevID].sc.cdsc_absaddr.msf.second,
+		CDADev[wDevID].sc.cdsc_absaddr.msf.frame
 #elif __FreeBSD__
-		CDADev[index].sc.what.position.track_number,
-		CDADev[index].sc.what.position.absaddr.msf.minute,
-		CDADev[index].sc.what.position.absaddr.msf.second,
-		CDADev[index].sc.what.position.absaddr.msf.frame
+		CDADev[wDevID].sc.what.position.track_number,
+		CDADev[wDevID].sc.what.position.absaddr.msf.minute,
+		CDADev[wDevID].sc.what.position.absaddr.msf.second,
+		CDADev[wDevID].sc.what.position.absaddr.msf.frame
 #endif
 			);
-	if (oldmode != CDADev[index].mode && oldmode == MCI_MODE_OPEN) {
+	if (oldmode != CDADev[wDevID].mode && oldmode == MCI_MODE_OPEN) {
 		if (!CDAUDIO_GetTracksInfo(wDevID)) {
             dprintf_cdaudio(stddeb,"CDAUDIO_GetCDStatus // error updating TracksInfo !\n");
 			return MCIERR_INTERNAL;
@@ -569,11 +559,11 @@
 {
 	DWORD	dwTime = 0;
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	UINT16	wTrack;
 	UINT16	wMinutes;
 	UINT16	wSeconds;
 	UINT16	wFrames;
+
     	dprintf_cdaudio(stddeb,"CDAUDIO_CalcTime(%04X, %08lX, %lu);\n", 
 		wDevID, dwFormatType, dwFrame);
 
@@ -597,11 +587,11 @@
 			/* unknown format ! force TMSF ! ... */
 			dwFormatType = MCI_FORMAT_TMSF;
 		case MCI_FORMAT_TMSF:
-			for (wTrack = 0; wTrack < CDADev[index].nTracks; wTrack++) {
-/*				dwTime += CDADev[index].lpdwTrackLen[wTrack - 1];
+			for (wTrack = 0; wTrack < CDADev[wDevID].nTracks; wTrack++) {
+/*				dwTime += CDADev[wDevID].lpdwTrackLen[wTrack - 1];
 				printf("Adding trk#%u curpos=%u \n", dwTime);
 				if (dwTime >= dwFrame) break; */
-				if (CDADev[index].lpdwTrackPos[wTrack - 1] >= dwFrame) break;
+				if (CDADev[wDevID].lpdwTrackPos[wTrack - 1] >= dwFrame) break;
 				}
 			wMinutes = dwFrame / CDFRAMES_PERMIN;
 			wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
@@ -624,27 +614,26 @@
 static DWORD CDAUDIO_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
     	dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus(%04X, %08lX, %p);\n", 
 		wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
-	if (CDADev[index].unixdev == 0) return MMSYSERR_NOTENABLED;
+	if (CDADev[wDevID].unixdev == 0) return MMSYSERR_NOTENABLED;
 	if (dwFlags & MCI_NOTIFY) {
         	dprintf_cdaudio(stddeb,
 			"CDAUDIO_mciStatus // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			CDADev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
 	if (dwFlags & MCI_STATUS_ITEM) {
 		switch(lpParms->dwItem) {
 			case MCI_STATUS_CURRENT_TRACK:
 				if (!CDAUDIO_GetCDStatus(wDevID)) return MCIERR_INTERNAL;
-				lpParms->dwReturn = CDADev[index].nCurTrack;
+				lpParms->dwReturn = CDADev[wDevID].nCurTrack;
                 		dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
 			 	return 0;
 			case MCI_STATUS_LENGTH:
-				if (CDADev[index].nTracks == 0) {
+				if (CDADev[wDevID].nTracks == 0) {
 					if (!CDAUDIO_GetTracksInfo(wDevID)) {
                         			dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // error reading TracksInfo !\n");
 						return MCIERR_INTERNAL;
@@ -653,24 +642,24 @@
 				if (dwFlags & MCI_TRACK) {
 					dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // MCI_TRACK #%lu LENGTH=??? !\n",
 							lpParms->dwTrack);
-					if (lpParms->dwTrack > CDADev[index].nTracks)
+					if (lpParms->dwTrack > CDADev[wDevID].nTracks)
 						return MCIERR_OUTOFRANGE;
-					lpParms->dwReturn = CDADev[index].lpdwTrackLen[lpParms->dwTrack];
+					lpParms->dwReturn = CDADev[wDevID].lpdwTrackLen[lpParms->dwTrack];
 					}
 				else
-					lpParms->dwReturn = CDADev[index].dwTotalLen;
+					lpParms->dwReturn = CDADev[wDevID].dwTotalLen;
 				lpParms->dwReturn = CDAUDIO_CalcTime(wDevID, 
-					CDADev[index].dwTimeFormat, lpParms->dwReturn);
+					CDADev[wDevID].dwTimeFormat, lpParms->dwReturn);
                 		dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // LENGTH=%lu !\n", lpParms->dwReturn);
 			 	return 0;
 			case MCI_STATUS_MODE:
 				if (!CDAUDIO_GetCDStatus(wDevID)) return MCIERR_INTERNAL;
-				lpParms->dwReturn = CDADev[index].mode;
+				lpParms->dwReturn = CDADev[wDevID].mode;
                 		dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // MCI_STATUS_MODE=%08lX !\n",
 												lpParms->dwReturn);
 			 	return 0;
 			case MCI_STATUS_MEDIA_PRESENT:
-				lpParms->dwReturn = (CDADev[index].nTracks > 0) ? TRUE : FALSE;
+				lpParms->dwReturn = (CDADev[wDevID].nTracks > 0) ? TRUE : FALSE;
 				if (lpParms->dwReturn == FALSE)
                     			dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // MEDIA_NOT_PRESENT !\n");
 				else
@@ -684,19 +673,19 @@
 			 	return 0;
 			case MCI_STATUS_POSITION:
 				if (!CDAUDIO_GetCDStatus(wDevID)) return MCIERR_INTERNAL;
-				lpParms->dwReturn = CDADev[index].dwCurFrame;
+				lpParms->dwReturn = CDADev[wDevID].dwCurFrame;
 				if (dwFlags & MCI_STATUS_START) {
-					lpParms->dwReturn = CDADev[index].dwFirstOffset;
+					lpParms->dwReturn = CDADev[wDevID].dwFirstOffset;
                     			dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // get MCI_STATUS_START !\n");
 					}
 				if (dwFlags & MCI_TRACK) {
-					if (lpParms->dwTrack > CDADev[index].nTracks)
+					if (lpParms->dwTrack > CDADev[wDevID].nTracks)
 						return MCIERR_OUTOFRANGE;
-					lpParms->dwReturn = CDADev[index].lpdwTrackPos[lpParms->dwTrack - 1];
+					lpParms->dwReturn = CDADev[wDevID].lpdwTrackPos[lpParms->dwTrack - 1];
                     			dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // get MCI_TRACK #%lu !\n", lpParms->dwTrack);
 					}
 				lpParms->dwReturn = CDAUDIO_CalcTime(wDevID,
-					CDADev[index].dwTimeFormat, lpParms->dwReturn);
+					CDADev[wDevID].dwTimeFormat, lpParms->dwReturn);
                 			dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // MCI_STATUS_POSITION=%08lX !\n",
 														lpParms->dwReturn);
 			 	return 0;
@@ -706,7 +695,7 @@
 			 	return 0;
 			case MCI_STATUS_TIME_FORMAT:
                 		dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // MCI_STATUS_TIME_FORMAT !\n");
-				lpParms->dwReturn = CDADev[index].dwTimeFormat;
+				lpParms->dwReturn = CDADev[wDevID].dwTimeFormat;
 			 	return 0;
 			default:
                 		dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // unknown command %08lX !\n", lpParms->dwItem);
@@ -727,34 +716,34 @@
 static DWORD CDAUDIO_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	int 	start, end;
 #ifdef linux
 	struct 	cdrom_msf	msf;
 #elif __FreeBSD__
 	struct	ioc_play_msf	msf;
 #endif
+
     	dprintf_cdaudio(stddeb,"CDAUDIO_mciPlay(%04X, %08lX, %p);\n", 
 		wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
-	if (CDADev[index].unixdev == 0) return MMSYSERR_NOTENABLED;
-	start = 0; 		end = CDADev[index].dwTotalLen;
-	CDADev[index].nCurTrack = 1;
+	if (CDADev[wDevID].unixdev == 0) return MMSYSERR_NOTENABLED;
+	start = 0; 		end = CDADev[wDevID].dwTotalLen;
+	CDADev[wDevID].nCurTrack = 1;
 	if (dwFlags & MCI_FROM) {
 		start = CDAUDIO_CalcFrame(wDevID, 
-			CDADev[index].dwTimeFormat, lpParms->dwFrom); 
+			CDADev[wDevID].dwTimeFormat, lpParms->dwFrom); 
         dprintf_cdaudio(stddeb,"CDAUDIO_mciPlay // MCI_FROM=%08lX -> %u \n",
 				lpParms->dwFrom, start);
 		}
 	if (dwFlags & MCI_TO) {
 		end = CDAUDIO_CalcFrame(wDevID, 
-			CDADev[index].dwTimeFormat, lpParms->dwTo);
+			CDADev[wDevID].dwTimeFormat, lpParms->dwTo);
         	dprintf_cdaudio(stddeb,
 			"CDAUDIO_mciPlay // MCI_TO=%08lX -> %u \n",
 			lpParms->dwTo, end);
 		}
-	start += CDADev[index].dwFirstOffset;	
-	end += CDADev[index].dwFirstOffset;
+	start += CDADev[wDevID].dwFirstOffset;	
+	end += CDADev[wDevID].dwFirstOffset;
 #ifdef linux
 	msf.cdmsf_min0 = start / CDFRAMES_PERMIN;
 	msf.cdmsf_sec0 = (start % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
@@ -770,7 +759,7 @@
         msf.end_s       = (end % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
         msf.end_f       = end % CDFRAMES_PERSEC;
 #endif
-	if (ioctl(CDADev[index].unixdev,
+	if (ioctl(CDADev[wDevID].unixdev,
 #ifdef linux
 		  CDROMSTART
 #elif __FreeBSD__
@@ -780,7 +769,7 @@
         	dprintf_cdaudio(stddeb,"CDAUDIO_mciPlay // motor doesn't start !\n");
 		return MCIERR_HARDWARE;
 		}
-	if (ioctl(CDADev[index].unixdev, 
+	if (ioctl(CDADev[wDevID].unixdev, 
 #ifdef linux
 		  CDROMPLAYMSF
 #elif __FreeBSD__
@@ -799,14 +788,14 @@
 		msf.end_m,   msf.end_s,   msf.end_f
 #endif
 			);
-	CDADev[index].mode = MCI_MODE_PLAY;
+	CDADev[wDevID].mode = MCI_MODE_PLAY;
 	if (dwFlags & MCI_NOTIFY) {
         	dprintf_cdaudio(stddeb,
 			"CDAUDIO_mciPlay // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 /*
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			CDADev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 */
 		}
 	return 0;
@@ -821,24 +810,23 @@
 static DWORD CDAUDIO_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
     	dprintf_cdaudio(stddeb,"CDAUDIO_mciStop(%04X, %08lX, %p);\n", 
 		wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
-	if (ioctl(CDADev[index].unixdev,
+	if (ioctl(CDADev[wDevID].unixdev,
 #ifdef linux
 		  CDROMSTOP
 #elif __FreeBSD__
 		  CDIOCSTOP
 #endif
 		  )) return MCIERR_HARDWARE;
-	CDADev[index].mode = MCI_MODE_STOP;
+	CDADev[wDevID].mode = MCI_MODE_STOP;
 	if (dwFlags & MCI_NOTIFY) {
         	dprintf_cdaudio(stddeb,
 			"CDAUDIO_mciStop // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			CDADev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
  	return 0;
 #else
@@ -852,24 +840,23 @@
 static DWORD CDAUDIO_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
     	dprintf_cdaudio(stddeb,"CDAUDIO_mciPause(%04X, %08lX, %p);\n", 
 		wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
-	if (ioctl(CDADev[index].unixdev,
+	if (ioctl(CDADev[wDevID].unixdev,
 #ifdef linux
 		  CDROMPAUSE
 #elif __FreeBSD__
 		  CDIOCPAUSE
 #endif
 		  )) return MCIERR_HARDWARE;
-	CDADev[index].mode = MCI_MODE_PAUSE;
+	CDADev[wDevID].mode = MCI_MODE_PAUSE;
 	if (dwFlags & MCI_NOTIFY) {
         dprintf_cdaudio(stddeb,
 		"CDAUDIO_mciPause // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 		lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			CDADev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
 	return 0;
 #else
@@ -883,24 +870,23 @@
 static DWORD CDAUDIO_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
     	dprintf_cdaudio(stddeb,"CDAUDIO_mciResume(%04X, %08lX, %p);\n", 
 		wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
-	if (ioctl(CDADev[index].unixdev, 
+	if (ioctl(CDADev[wDevID].unixdev, 
 #ifdef linux
 		  CDROMRESUME
 #elif __FreeBSD__
 		  CDIOCRESUME
 #endif
 		  )) return MCIERR_HARDWARE;
-	CDADev[index].mode = MCI_MODE_STOP;
+	CDADev[wDevID].mode = MCI_MODE_STOP;
 	if (dwFlags & MCI_NOTIFY) {
         	dprintf_cdaudio(stddeb,
 			"CDAUDIO_mciResume // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			CDADev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
 	return 0;
 #else
@@ -914,13 +900,12 @@
 static DWORD CDAUDIO_mciSeek(UINT16 wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	DWORD	dwRet;
 	MCI_PLAY_PARMS PlayParms;
     	dprintf_cdaudio(stddeb,"CDAUDIO_mciSeek(%04X, %08lX, %p);\n", 
 		wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
-	if (ioctl(CDADev[index].unixdev,
+	if (ioctl(CDADev[wDevID].unixdev,
 #ifdef linux
 		  CDROMRESUME
 #elif __FreeBSD__
@@ -930,13 +915,13 @@
 		perror("ioctl CDROMRESUME");
 		return MCIERR_HARDWARE;
 	}
-	CDADev[index].mode = MCI_MODE_SEEK;
+	CDADev[wDevID].mode = MCI_MODE_SEEK;
 	switch(dwFlags) {
 		case MCI_SEEK_TO_START:
 			PlayParms.dwFrom = 0;
 			break;
 		case MCI_SEEK_TO_END:
-			PlayParms.dwFrom = CDADev[index].dwTotalLen;
+			PlayParms.dwFrom = CDADev[wDevID].dwTotalLen;
 			break;
 		case MCI_TO:
 			PlayParms.dwFrom = lpParms->dwTo;
@@ -950,7 +935,7 @@
 			"CDAUDIO_mciSeek // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			CDADev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
 	return dwRet;
 #else
@@ -965,7 +950,6 @@
 static DWORD CDAUDIO_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
     	dprintf_cdaudio(stddeb,"CDAUDIO_mciSet(%04X, %08lX, %p);\n", 
 		wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
@@ -989,32 +973,32 @@
                 		dprintf_cdaudio(stddeb,"CDAUDIO_mciSet // bad time format !\n");
 				return MCIERR_BAD_TIME_FORMAT;
 			}
-		CDADev[index].dwTimeFormat = lpParms->dwTimeFormat;
+		CDADev[wDevID].dwTimeFormat = lpParms->dwTimeFormat;
 		}
 	if (dwFlags & MCI_SET_DOOR_OPEN) {
         	dprintf_cdaudio(stddeb,
 			"CDAUDIO_mciSet // MCI_SET_DOOR_OPEN !\n");
 #ifdef __FreeBSD__
-		if (ioctl(CDADev[index].unixdev, CDIOCALLOW)) return MCIERR_HARDWARE;
-		if (ioctl(CDADev[index].unixdev, CDIOCEJECT)) return MCIERR_HARDWARE;
-		if (ioctl(CDADev[index].unixdev, CDIOCPREVENT)) return MCIERR_HARDWARE;
+		if (ioctl(CDADev[wDevID].unixdev, CDIOCALLOW)) return MCIERR_HARDWARE;
+		if (ioctl(CDADev[wDevID].unixdev, CDIOCEJECT)) return MCIERR_HARDWARE;
+		if (ioctl(CDADev[wDevID].unixdev, CDIOCPREVENT)) return MCIERR_HARDWARE;
 #elif linux
-		if (ioctl(CDADev[index].unixdev, CDROMEJECT)) return MCIERR_HARDWARE;
+		if (ioctl(CDADev[wDevID].unixdev, CDROMEJECT)) return MCIERR_HARDWARE;
 #endif
-		CDADev[index].nTracks = 0;
+		CDADev[wDevID].nTracks = 0;
 		}
 	if (dwFlags & MCI_SET_DOOR_CLOSED) {
         	dprintf_cdaudio(stddeb,
 			"CDAUDIO_mciSet // MCI_SET_DOOR_CLOSED !\n");
 #ifdef __FreeBSD__
-                if (ioctl(CDADev[index].unixdev, CDIOCALLOW)) return MCIERR_HARDWARE;
-                if (ioctl(CDADev[index].unixdev, CDIOCCLOSE)) return MCIERR_HARDWARE;
-                if (ioctl(CDADev[index].unixdev, CDIOCPREVENT)) return MCIERR_HARDWARE;
+                if (ioctl(CDADev[wDevID].unixdev, CDIOCALLOW)) return MCIERR_HARDWARE;
+                if (ioctl(CDADev[wDevID].unixdev, CDIOCCLOSE)) return MCIERR_HARDWARE;
+                if (ioctl(CDADev[wDevID].unixdev, CDIOCPREVENT)) return MCIERR_HARDWARE;
 #elif linux
-		if (ioctl(CDADev[index].unixdev, CDROMEJECT)) return MCIERR_HARDWARE;
+		if (ioctl(CDADev[wDevID].unixdev, CDROMEJECT)) return MCIERR_HARDWARE;
 			  /* XXX should it be ",1" ??? */
 #endif
-		CDADev[index].nTracks = 0;
+		CDADev[wDevID].nTracks = 0;
 		}
 	if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
 	if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
@@ -1024,7 +1008,7 @@
 			"CDAUDIO_mciSet // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 			lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			CDADev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
 	return 0;
 #else
diff --git a/multimedia/mcistring.c b/multimedia/mcistring.c
index f61679c..429f2b2 100644
--- a/multimedia/mcistring.c
+++ b/multimedia/mcistring.c
@@ -311,6 +311,7 @@
 	if (s!=NULL) {
 		*s++='\0';
 		pU->openParams.lpstrElementName=SEGPTR_GET(SEGPTR_STRDUP(s));
+		dwFlags |= MCI_OPEN_ELEMENT;
 	}
 	if (!STRCMP(dev,"cdaudio")) {
 		uDevTyp=MCI_DEVTYPE_CD_AUDIO;
@@ -338,7 +339,7 @@
 		}
 	}
 	GetDrv(wDevID)->wType		= uDevTyp;
-	GetDrv(wDevID)->wDeviceID	= wDevID;
+	GetDrv(wDevID)->wDeviceID	= 0;  /* FIXME? for multiple devices */
 	pU->openParams.dwCallback	= 0;
 	pU->openParams.wDeviceID	= wDevID;
 	pU->ovlyopenParams.dwStyle	= 0; 
diff --git a/multimedia/midi.c b/multimedia/midi.c
index 7a52f87..a4446e3 100644
--- a/multimedia/midi.c
+++ b/multimedia/midi.c
@@ -11,6 +11,7 @@
 #include <sys/ioctl.h>
 #include "windows.h"
 #include "ldt.h"
+#include "user.h"
 #include "driver.h"
 #include "mmsystem.h"
 #include "xmalloc.h"
@@ -24,8 +25,6 @@
 #include <machine/soundcard.h>
 #endif
 
-int MMSYSTEM_DevIDToIndex(UINT16);
-
 #if defined(linux) || defined(__FreeBSD__)
 #define MIDI_DEV "/dev/sequencer"
 
@@ -35,9 +34,9 @@
 #define IOCTL(a,b,c)		(c = ioctl(a,b,c) )
 #endif
 
-#define MAX_MIDIINDRV 	2
-#define MAX_MIDIOUTDRV 	2
-#define MAX_MCIMIDIDRV 	2
+#define MAX_MIDIINDRV 	(1)
+#define MAX_MIDIOUTDRV 	(1)
+#define MAX_MCIMIDIDRV 	(1)
 
 typedef struct {
 	int				unixdev;
@@ -71,7 +70,8 @@
 	WORD	nTracks;
 	WORD	nTempo;
 	MCI_OPEN_PARMS openParms;
-	MIDIHDR		MidiHdr;
+/* 	MIDIHDR		MidiHdr; */
+	HLOCAL16        hMidiHdr;
 	WORD		dwStatus;
 	} LINUX_MCIMIDI;
 
@@ -88,11 +88,10 @@
 				DWORD dwParam1, DWORD dwParam2)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
-	if (MidiInDev[index].wFlags != DCB_NULL && !DriverCallback(
-		MidiInDev[index].midiDesc.dwCallback, MidiInDev[index].wFlags, 
-		MidiInDev[index].midiDesc.hMidi, wMsg, 
-		MidiInDev[index].midiDesc.dwInstance, dwParam1, dwParam2)) {
+	if (MidiInDev[wDevID].wFlags != DCB_NULL && !DriverCallback(
+		MidiInDev[wDevID].midiDesc.dwCallback, MidiInDev[wDevID].wFlags, 
+		MidiInDev[wDevID].midiDesc.hMidi, wMsg, 
+		MidiInDev[wDevID].midiDesc.dwInstance, dwParam1, dwParam2)) {
 		dprintf_midi(stddeb, "MIDI_NotifyClient // can't notify client !\n");
 		return MMSYSERR_NOERROR;
 		}
@@ -108,10 +107,9 @@
 */
 static DWORD MIDI_ReadByte(UINT16 wDevID, BYTE *lpbyt)
 {
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 #if defined(linux) || defined(__FreeBSD__)
 	if (lpbyt != NULL) {
-		if (mmioRead(MCIMidiDev[index].hFile, (HPSTR)lpbyt,
+		if (mmioRead(MCIMidiDev[wDevID].hFile, (HPSTR)lpbyt,
 			(long) sizeof(BYTE)) == (long) sizeof(BYTE)) {
 			return 0;
 			}
@@ -197,34 +195,33 @@
 static DWORD MIDI_ReadMThd(UINT16 wDevID, DWORD dwOffset)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	DWORD	toberead;
 	FOURCC	fourcc;
 	dprintf_midi(stddeb, "MIDI_ReadMThd(%04X, %08lX);\n", wDevID, dwOffset);
-	if (mmioSeek(MCIMidiDev[index].hFile, dwOffset, SEEK_SET) != dwOffset) {
+	if (mmioSeek(MCIMidiDev[wDevID].hFile, dwOffset, SEEK_SET) != dwOffset) {
 		dprintf_midi(stddeb, "MIDI_ReadMThd // can't seek at %08lX begin of 'MThd' \n", dwOffset);
 		return MCIERR_INTERNAL;
 		}
-	if (mmioRead(MCIMidiDev[index].hFile, (HPSTR)&fourcc,
+	if (mmioRead(MCIMidiDev[wDevID].hFile, (HPSTR)&fourcc,
 		(long) sizeof(FOURCC)) != (long) sizeof(FOURCC)) {
 		return MCIERR_INTERNAL;
 		}
 	if (MIDI_ReadLong(wDevID, &toberead) != 0) {
 		return MCIERR_INTERNAL;
 		}
-	if (MIDI_ReadWord(wDevID, &MCIMidiDev[index].wFormat) != 0) {
+	if (MIDI_ReadWord(wDevID, &MCIMidiDev[wDevID].wFormat) != 0) {
 		return MCIERR_INTERNAL;
 		}
-	if (MIDI_ReadWord(wDevID, &MCIMidiDev[index].nTracks) != 0) {
+	if (MIDI_ReadWord(wDevID, &MCIMidiDev[wDevID].nTracks) != 0) {
 		return MCIERR_INTERNAL;
 		}
-	if (MIDI_ReadWord(wDevID, &MCIMidiDev[index].nTempo) != 0) {
+	if (MIDI_ReadWord(wDevID, &MCIMidiDev[wDevID].nTempo) != 0) {
 		return MCIERR_INTERNAL;
 		}
 	dprintf_midi(stddeb, "MIDI_ReadMThd // toberead=%08lX, wFormat=%04X nTracks=%04X nTempo=%04X\n",
-		toberead, MCIMidiDev[index].wFormat,
-		MCIMidiDev[index].nTracks,
-		MCIMidiDev[index].nTempo);
+		toberead, MCIMidiDev[wDevID].wFormat,
+		MCIMidiDev[wDevID].nTracks,
+		MCIMidiDev[wDevID].nTempo);
 	toberead -= 3 * sizeof(WORD);
 /*
 		ntrks = read16bit ();
@@ -241,13 +238,12 @@
 static DWORD MIDI_ReadMTrk(UINT16 wDevID, DWORD dwOffset)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	DWORD	toberead;
 	FOURCC	fourcc;
-	if (mmioSeek(MCIMidiDev[index].hFile, dwOffset, SEEK_SET) != dwOffset) {
+	if (mmioSeek(MCIMidiDev[wDevID].hFile, dwOffset, SEEK_SET) != dwOffset) {
 		dprintf_midi(stddeb, "MIDI_ReadMTrk // can't seek at %08lX begin of 'MThd' \n", dwOffset);
 		}
-	if (mmioRead(MCIMidiDev[index].hFile, (HPSTR)&fourcc,
+	if (mmioRead(MCIMidiDev[wDevID].hFile, (HPSTR)&fourcc,
 		(long) sizeof(FOURCC)) != (long) sizeof(FOURCC)) {
 		return MCIERR_INTERNAL;
 		}
@@ -256,7 +252,7 @@
 		}
 	dprintf_midi(stddeb, "MIDI_ReadMTrk // toberead=%08lX\n", toberead);
 	toberead -= 3 * sizeof(WORD);
-	MCIMidiDev[index].dwTotalLen = toberead;
+	MCIMidiDev[wDevID].dwTotalLen = toberead;
 	return 0;
 #else
          return MMSYSERR_NOTENABLED;
@@ -270,7 +266,6 @@
 static DWORD MIDI_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_OPEN_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index;
 	MIDIOPENDESC 	MidiDesc;
 	DWORD		dwRet;
 	DWORD		dwOffset;
@@ -280,24 +275,22 @@
 	dprintf_midi(stddeb, "MIDI_mciOpen(%08lX, %p)\n", dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
 
-	wDevID = lpParms->wDeviceID;
-	index = MMSYSTEM_DevIDToIndex(wDevID);
-
-	if (MCIMidiDev[index].nUseCount > 0) {
+	if (MCIMidiDev[wDevID].nUseCount > 0) {
 		/* The driver already open on this channel */
 		/* If the driver was opened shareable before and this open specifies */
 		/* shareable then increment the use count */
-		if (MCIMidiDev[index].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
-			++MCIMidiDev[index].nUseCount;
+		if (MCIMidiDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
+			++MCIMidiDev[wDevID].nUseCount;
 		else
 			return MCIERR_MUST_USE_SHAREABLE;
 		}
 	else {
-		MCIMidiDev[index].nUseCount = 1;
-		MCIMidiDev[index].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
+		MCIMidiDev[wDevID].nUseCount = 1;
+		MCIMidiDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
+		MCIMidiDev[wDevID].hMidiHdr = USER_HEAP_ALLOC(sizeof(MIDIHDR));
 		}
 	dprintf_midi(stddeb, "MIDI_mciOpen // wDevID=%04X\n", wDevID);
-	lpParms->wDeviceID = wDevID;
+/*	lpParms->wDeviceID = wDevID;*/
 	dprintf_midi(stddeb, "MIDI_mciOpen // lpParms->wDevID=%04X\n", lpParms->wDeviceID);
 	dprintf_midi(stddeb, "MIDI_mciOpen // before OPEN_ELEMENT\n");
 	if (dwFlags & MCI_OPEN_ELEMENT) {
@@ -306,26 +299,26 @@
 		if (strlen(lpstrElementName) > 0) {
 			strcpy(str, lpstrElementName);
 			CharUpper32A(str);
-			MCIMidiDev[index].hFile = mmioOpen(str, NULL, 
+			MCIMidiDev[wDevID].hFile = mmioOpen(str, NULL, 
 				MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE);
-			if (MCIMidiDev[index].hFile == 0) {
+			if (MCIMidiDev[wDevID].hFile == 0) {
 				dprintf_midi(stddeb, "MIDI_mciOpen // can't find file='%s' !\n", str);
 				return MCIERR_FILE_NOT_FOUND;
 				}
 			}
 		else 
-			MCIMidiDev[index].hFile = 0;
+			MCIMidiDev[wDevID].hFile = 0;
 		}
-	dprintf_midi(stddeb, "MIDI_mciOpen // hFile=%u\n", MCIMidiDev[index].hFile);
-	memcpy(&MCIMidiDev[index].openParms, lpParms, sizeof(MCI_OPEN_PARMS));
-	MCIMidiDev[index].wNotifyDeviceID = lpParms->wDeviceID;
-	MCIMidiDev[index].dwStatus = MCI_MODE_STOP;
-	MCIMidiDev[index].dwBeginData = 0;
-	MCIMidiDev[index].dwTotalLen = 0;
+	dprintf_midi(stddeb, "MIDI_mciOpen // hFile=%u\n", MCIMidiDev[wDevID].hFile);
+	memcpy(&MCIMidiDev[wDevID].openParms, lpParms, sizeof(MCI_OPEN_PARMS));
+	MCIMidiDev[wDevID].wNotifyDeviceID = lpParms->wDeviceID;
+	MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
+	MCIMidiDev[wDevID].dwBeginData = 0;
+	MCIMidiDev[wDevID].dwTotalLen = 0;
 	MidiDesc.hMidi = 0;
-	if (MCIMidiDev[index].hFile != 0) {
+	if (MCIMidiDev[wDevID].hFile != 0) {
 		MMCKINFO	ckMainRIFF;
-		if (mmioDescend(MCIMidiDev[index].hFile, &ckMainRIFF, NULL, 0) != 0) {
+		if (mmioDescend(MCIMidiDev[wDevID].hFile, &ckMainRIFF, NULL, 0) != 0) {
 			return MCIERR_INTERNAL;
 			}
 		dprintf_midi(stddeb,"MIDI_mciOpen // ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
@@ -344,19 +337,19 @@
 			dprintf_midi(stddeb, "MIDI_mciOpen // can't read 'MThd' header \n");
 			return MCIERR_INTERNAL;
 			}
-		dwOffset = mmioSeek(MCIMidiDev[index].hFile, 0, SEEK_CUR);
+		dwOffset = mmioSeek(MCIMidiDev[wDevID].hFile, 0, SEEK_CUR);
 		if (MIDI_ReadMTrk(wDevID, dwOffset) != 0) {
 			dprintf_midi(stddeb, "MIDI_mciOpen // can't read 'MTrk' header \n");
 			return MCIERR_INTERNAL;
 			}
-		dwOffset = mmioSeek(MCIMidiDev[index].hFile, 0, SEEK_CUR);
-		MCIMidiDev[index].dwBeginData = dwOffset;
+		dwOffset = mmioSeek(MCIMidiDev[wDevID].hFile, 0, SEEK_CUR);
+		MCIMidiDev[wDevID].dwBeginData = dwOffset;
 		dprintf_midi(stddeb, "MIDI_mciOpen // Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
 				(LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
 				ckMainRIFF.cksize);
 		}
 	dwRet = modMessage(wDevID, MODM_OPEN, 0, (DWORD)&MidiDesc, CALLBACK_NULL);
-	dwRet = midMessage(wDevID, MIDM_OPEN, 0, (DWORD)&MidiDesc, CALLBACK_NULL);
+/*	dwRet = midMessage(wDevID, MIDM_OPEN, 0, (DWORD)&MidiDesc, CALLBACK_NULL); */
 	return 0;
 #else
 	return MMSYSERR_NOTENABLED;
@@ -370,12 +363,11 @@
 static DWORD MIDI_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_midi(stddeb, "MIDI_mciStop(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
-	MCIMidiDev[index].dwStatus = MCI_MODE_STOP;
-	dprintf_midi(stddeb, "MIDI_mciStop // MCIMidiDev[index].dwStatus=%p %d\n",
-			&MCIMidiDev[index].dwStatus, MCIMidiDev[index].dwStatus);
+	MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
+	dprintf_midi(stddeb, "MIDI_mciStop // MCIMidiDev[wDevID].dwStatus=%p %d\n",
+			&MCIMidiDev[wDevID].dwStatus, MCIMidiDev[wDevID].dwStatus);
 	return 0;
 #else
 	return MCIERR_INTERNAL;
@@ -389,24 +381,27 @@
 static DWORD MIDI_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	DWORD		dwRet;
+
 	dprintf_midi(stddeb, "MIDI_mciClose(%04X, %08lX, %p);\n", wDevID, dwParam, lpParms);
-	if (MCIMidiDev[index].dwStatus != MCI_MODE_STOP) {
+	if (MCIMidiDev[wDevID].dwStatus != MCI_MODE_STOP) {
 		MIDI_mciStop(wDevID, MCI_WAIT, lpParms);
 		}
-	MCIMidiDev[index].dwStatus = MCI_MODE_STOP;
-	MCIMidiDev[index].nUseCount--;
-	if (MCIMidiDev[index].nUseCount == 0) {
-		if (MCIMidiDev[index].hFile != 0) {
-			mmioClose(MCIMidiDev[index].hFile, 0);
-			MCIMidiDev[index].hFile = 0;
+	MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
+	MCIMidiDev[wDevID].nUseCount--;
+	if (MCIMidiDev[wDevID].nUseCount == 0) {
+		if (MCIMidiDev[wDevID].hFile != 0) {
+			mmioClose(MCIMidiDev[wDevID].hFile, 0);
+			MCIMidiDev[wDevID].hFile = 0;
 			dprintf_midi(stddeb, "MIDI_mciClose // hFile closed !\n");
 			}
+		USER_HEAP_FREE(MCIMidiDev[wDevID].hMidiHdr);
 		dwRet = modMessage(wDevID, MODM_CLOSE, 0, 0L, 0L);
 		if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
+/*
 		dwRet = midMessage(wDevID, MIDM_CLOSE, 0, 0L, 0L);
 		if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
+*/
 		}
 	return 0;
 #else
@@ -421,17 +416,18 @@
 static DWORD MIDI_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	int			count;
 	int			start, end;
 	LPMIDIHDR	lpMidiHdr;
+	DWORD           lp16MidiHdr;
 	DWORD		dwData;
 	LPWORD		ptr;
 	DWORD		dwRet;
+
 	dprintf_midi(stddeb, "MIDI_mciPlay(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-	if (MCIMidiDev[index].hFile == 0) {
+	if (MCIMidiDev[wDevID].hFile == 0) {
 		dprintf_midi(stddeb, "MIDI_mciPlay // can't find file='%08lx' !\n", 
-				MCIMidiDev[index].openParms.lpstrElementName);
+				MCIMidiDev[wDevID].openParms.lpstrElementName);
 		return MCIERR_FILE_NOT_FOUND;
 		}
 	start = 1; 		end = 99999;
@@ -459,51 +455,80 @@
 			}
 		}
 #endif
-	lpMidiHdr = &MCIMidiDev[index].MidiHdr;
+
+	lpMidiHdr = USER_HEAP_LIN_ADDR(MCIMidiDev[wDevID].hMidiHdr);
+	lp16MidiHdr = USER_HEAP_SEG_ADDR(MCIMidiDev[wDevID].hMidiHdr);
+
 	lpMidiHdr->lpData = (LPSTR) malloc(1200);
 	if (lpMidiHdr->lpData == NULL) return MCIERR_INTERNAL;
 	lpMidiHdr->dwBufferLength = 1024;
 	lpMidiHdr->dwUser = 0L;
 	lpMidiHdr->dwFlags = 0L;
-	dwRet = modMessage(wDevID, MODM_PREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
+	dwRet = modMessage(wDevID, MODM_PREPARE, 0, (DWORD)lp16MidiHdr, sizeof(MIDIHDR));
+
 /*	dprintf_midi(stddeb, "MIDI_mciPlay // after MODM_PREPARE \n"); */
-	MCIMidiDev[index].dwStatus = MCI_MODE_PLAY;
-	while(MCIMidiDev[index].dwStatus != MCI_MODE_STOP) {
-		dprintf_midi(stddeb, "MIDI_mciPlay // MCIMidiDev[index].dwStatus=%p %d\n",
-			&MCIMidiDev[index].dwStatus, MCIMidiDev[index].dwStatus);
+
+	MCIMidiDev[wDevID].dwStatus = MCI_MODE_PLAY;
+	while(MCIMidiDev[wDevID].dwStatus != MCI_MODE_STOP) {
+		dprintf_midi(stddeb, "MIDI_mciPlay // MCIMidiDev[wDevID].dwStatus=%p %d\n",
+			&MCIMidiDev[wDevID].dwStatus, MCIMidiDev[wDevID].dwStatus);
+
 		ptr = (LPWORD)lpMidiHdr->lpData;
 		for (count = 0; count < lpMidiHdr->dwBufferLength; count++) {
 			if (MIDI_ReadVaryLen(wDevID, &dwData) != 0) break;
 			*ptr = LOWORD(dwData);
 			}
 /*
-		count = mmioRead(MCIMidiDev[index].hFile, lpMidiHdr->lpData, lpMidiHdr->dwBufferLength);
+		count = mmioRead(MCIMidiDev[wDevID].hFile, lpMidiHdr->lpData, lpMidiHdr->dwBufferLength);
 */
+		dprintf_midi(stddeb, "MIDI_mciPlay // after read count = %d\n",count);
+
 		if (count < 1) break;
 		lpMidiHdr->dwBytesRecorded = count;
 		dprintf_midi(stddeb, "MIDI_mciPlay // before MODM_LONGDATA lpMidiHdr=%p dwBytesRecorded=%lu\n",
 					lpMidiHdr, lpMidiHdr->dwBytesRecorded);
-		dwRet = modMessage(wDevID, MODM_LONGDATA, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
+		dwRet = modMessage(wDevID, MODM_LONGDATA, 0, (DWORD)lp16MidiHdr, sizeof(MIDIHDR));
+		if (dwRet != MMSYSERR_NOERROR) {
+		  switch (dwRet) {
+		  case MMSYSERR_NOTENABLED:
+		    return MCIERR_DEVICE_NOT_READY;
+		    
+		  case MIDIERR_NODEVICE:
+		    return MCIERR_INVALID_DEVICE_ID;
+
+		  case MIDIERR_UNPREPARED:
+		    return MCIERR_DRIVER_INTERNAL;
+
+		  case MIDIERR_STILLPLAYING:
+		    return MCIERR_SEQ_PORT_INUSE;
+
+		  case MMSYSERR_INVALPARAM:
+		    return MCIERR_CANNOT_LOAD_DRIVER;
+		  
+		  default:
+		    return MCIERR_DRIVER;
+		  }	
 		}
-	dwRet = modMessage(wDevID, MODM_UNPREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
+	      }
+	dwRet = modMessage(wDevID, MODM_UNPREPARE, 0, (DWORD)lp16MidiHdr, sizeof(MIDIHDR));
 	if (lpMidiHdr->lpData != NULL) {
 		free(lpMidiHdr->lpData);
 		lpMidiHdr->lpData = NULL;
-		}
-	MCIMidiDev[index].dwStatus = MCI_MODE_STOP;
+	      }
+	MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
 	if (dwFlags & MCI_NOTIFY) {
 		dprintf_midi(stddeb, "MIDI_mciPlay // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			MCIMidiDev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			MCIMidiDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 #if 0
 		exit(1);
 #endif
-		}
+	      }
 	return 0;
 #else
 	return MMSYSERR_NOTENABLED;
 #endif
-}
+      }
 
 
 /**************************************************************************
@@ -512,15 +537,14 @@
 static DWORD MIDI_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	int			start, end;
 	LPMIDIHDR	lpMidiHdr;
 	DWORD		dwRet;
 
 	dprintf_midi(stddeb, "MIDI_mciRecord(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-	if (MCIMidiDev[index].hFile == 0) {
+	if (MCIMidiDev[wDevID].hFile == 0) {
 		dprintf_midi(stddeb, "MIDI_mciRecord // can't find file='%08lx' !\n", 
-				MCIMidiDev[index].openParms.lpstrElementName);
+				MCIMidiDev[wDevID].openParms.lpstrElementName);
 		return MCIERR_FILE_NOT_FOUND;
 		}
 	start = 1; 		end = 99999;
@@ -532,17 +556,17 @@
 		end = lpParms->dwTo;
 		dprintf_midi(stddeb, "MIDI_mciRecord // MCI_TO=%d \n", end);
 		}
-	lpMidiHdr = &MCIMidiDev[index].MidiHdr;
+	lpMidiHdr = USER_HEAP_LIN_ADDR(MCIMidiDev[wDevID].hMidiHdr);
 	lpMidiHdr->lpData = (LPSTR) xmalloc(1200);
 	lpMidiHdr->dwBufferLength = 1024;
 	lpMidiHdr->dwUser = 0L;
 	lpMidiHdr->dwFlags = 0L;
 	dwRet = midMessage(wDevID, MIDM_PREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
 	dprintf_midi(stddeb, "MIDI_mciRecord // after MIDM_PREPARE \n");
-	MCIMidiDev[index].dwStatus = MCI_MODE_RECORD;
-	while(MCIMidiDev[index].dwStatus != MCI_MODE_STOP) {
-		dprintf_midi(stddeb, "MIDI_mciRecord // MCIMidiDev[index].dwStatus=%p %d\n",
-			&MCIMidiDev[index].dwStatus, MCIMidiDev[index].dwStatus);
+	MCIMidiDev[wDevID].dwStatus = MCI_MODE_RECORD;
+	while(MCIMidiDev[wDevID].dwStatus != MCI_MODE_STOP) {
+		dprintf_midi(stddeb, "MIDI_mciRecord // MCIMidiDev[wDevID].dwStatus=%p %d\n",
+			&MCIMidiDev[wDevID].dwStatus, MCIMidiDev[wDevID].dwStatus);
 		lpMidiHdr->dwBytesRecorded = 0;
 		dwRet = midMessage(wDevID, MIDM_START, 0, 0L, 0L);
 		dprintf_midi(stddeb, "MIDI_mciRecord // after MIDM_START lpMidiHdr=%p dwBytesRecorded=%lu\n",
@@ -556,11 +580,11 @@
 		free(lpMidiHdr->lpData);
 		lpMidiHdr->lpData = NULL;
 		}
-	MCIMidiDev[index].dwStatus = MCI_MODE_STOP;
+	MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
 	if (dwFlags & MCI_NOTIFY) {
 		dprintf_midi(stddeb, "MIDI_mciRecord // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			MCIMidiDev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			MCIMidiDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
 	return 0;
 #else
@@ -671,7 +695,6 @@
 static DWORD MIDI_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_midi(stddeb, "MIDI_mciStatus(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
 	if (lpParms == NULL) return MCIERR_INTERNAL;
 	if (dwFlags & MCI_STATUS_ITEM) {
@@ -746,7 +769,7 @@
 	if (dwFlags & MCI_NOTIFY) {
 		dprintf_midi(stddeb, "MIDI_mciStatus // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
 		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
-			MCIMidiDev[index].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			MCIMidiDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
 		}
  	return 0;
 #else
@@ -850,7 +873,6 @@
 static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	int		midi;
 	dprintf_midi(stddeb,
 		"midOpen(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
@@ -858,18 +880,18 @@
 		dprintf_midi(stddeb,"Linux 'midOpen' // Invalid Parameter !\n");
 		return MMSYSERR_INVALPARAM;
 		}
-	if (index >= MAX_MIDIINDRV) {
+	if (wDevID >= MAX_MIDIINDRV) {
 		dprintf_midi(stddeb,"Linux 'midOpen' // MAX_MIDIINDRV reached !\n");
 		return MMSYSERR_ALLOCATED;
 		}
-	MidiInDev[index].unixdev = 0;
+	MidiInDev[wDevID].unixdev = 0;
 	midi = open (MIDI_DEV, O_RDONLY, 0);
 	if (midi == -1) {
 		dprintf_midi(stddeb,"Linux 'midOpen' // can't open !\n");
 		return MMSYSERR_NOTENABLED;
 		}
-	MidiInDev[index].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
-	switch(MidiInDev[index].wFlags) {
+	MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
+	switch(MidiInDev[wDevID].wFlags) {
 		case DCB_NULL:
 			dprintf_midi(stddeb,"Linux 'midOpen' // CALLBACK_NULL !\n");
 			break;
@@ -886,10 +908,10 @@
 				   "Linux 'midOpen' // CALLBACK_FUNCTION !\n");
 			break;
 		}
-	MidiInDev[index].lpQueueHdr = NULL;
-	MidiInDev[index].unixdev = midi;
-	MidiInDev[index].dwTotalPlayed = 0;
-	MidiInDev[index].bufsize = 0x3FFF;
+	MidiInDev[wDevID].lpQueueHdr = NULL;
+	MidiInDev[wDevID].unixdev = midi;
+	MidiInDev[wDevID].dwTotalPlayed = 0;
+	MidiInDev[wDevID].bufsize = 0x3FFF;
 	if (MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
 		dprintf_midi(stddeb,"Linux 'midOpen' // can't notify client !\n");
 		return MMSYSERR_INVALPARAM;
@@ -906,15 +928,14 @@
 static DWORD midClose(WORD wDevID)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_midi(stddeb, "midClose(%04X);\n", wDevID);
-	if (MidiInDev[index].unixdev == 0) {
+	if (MidiInDev[wDevID].unixdev == 0) {
 		dprintf_midi(stddeb,"Linux 'midClose' // can't close !\n");
 		return MMSYSERR_NOTENABLED;
 		}
-	close(MidiInDev[index].unixdev);
-	MidiInDev[index].unixdev = 0;
-	MidiInDev[index].bufsize = 0;
+	close(MidiInDev[wDevID].unixdev);
+	MidiInDev[wDevID].unixdev = 0;
+	MidiInDev[wDevID].bufsize = 0;
 	if (MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
 		dprintf_midi(stddeb,"Linux 'midClose' // can't notify client !\n");
 		return MMSYSERR_INVALPARAM;
@@ -1034,28 +1055,28 @@
 * 				modOpen					[internal]
 */
 static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
-{								 
+{
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	int		midi;
+
 	dprintf_midi(stddeb,
 		"modOpen(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
 	if (lpDesc == NULL) {
 		dprintf_midi(stddeb,"Linux 'modOpen' // Invalid Parameter !\n");
 		return MMSYSERR_INVALPARAM;
 		}
-	if (index >= MAX_MIDIOUTDRV) {
+	if (wDevID>= MAX_MIDIOUTDRV) {
 		dprintf_midi(stddeb,"Linux 'modOpen' // MAX_MIDIOUTDRV reached !\n");
 		return MMSYSERR_ALLOCATED;
 		}
-	MidiOutDev[index].unixdev = 0;
+	MidiOutDev[wDevID].unixdev = 0;
 	midi = open (MIDI_DEV, O_WRONLY, 0);
 	if (midi == -1) {
 		dprintf_midi(stddeb,"Linux 'modOpen' // can't open !\n");
 		return MMSYSERR_NOTENABLED;
 		}
-	MidiOutDev[index].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
-	switch(MidiOutDev[index].wFlags) {
+	MidiOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
+	switch(MidiOutDev[wDevID].wFlags) {
 		case DCB_NULL:
 			dprintf_midi(stddeb,"Linux 'modOpen' // CALLBACK_NULL !\n");
 			break;
@@ -1072,10 +1093,10 @@
 				"Linux 'modOpen' // CALLBACK_FUNCTION !\n");
 			break;
 		}
-	MidiOutDev[index].lpQueueHdr = NULL;
-	MidiOutDev[index].unixdev = midi;
-	MidiOutDev[index].dwTotalPlayed = 0;
-	MidiOutDev[index].bufsize = 0x3FFF;
+	MidiOutDev[wDevID].lpQueueHdr = NULL;
+	MidiOutDev[wDevID].unixdev = midi;
+	MidiOutDev[wDevID].dwTotalPlayed = 0;
+	MidiOutDev[wDevID].bufsize = 0x3FFF;
 	if (MIDI_NotifyClient(wDevID, MOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
 		dprintf_midi(stddeb,"Linux 'modOpen' // can't notify client !\n");
 		return MMSYSERR_INVALPARAM;
@@ -1095,15 +1116,14 @@
 static DWORD modClose(WORD wDevID)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_midi(stddeb, "modClose(%04X);\n", wDevID);
-	if (MidiOutDev[index].unixdev == 0) {
+	if (MidiOutDev[wDevID].unixdev == 0) {
 		dprintf_midi(stddeb,"Linux 'modClose' // can't close !\n");
 		return MMSYSERR_NOTENABLED;
 		}
-	close(MidiOutDev[index].unixdev);
-	MidiOutDev[index].unixdev = 0;
-	MidiOutDev[index].bufsize = 0;
+	close(MidiOutDev[wDevID].unixdev);
+	MidiOutDev[wDevID].unixdev = 0;
+	MidiOutDev[wDevID].bufsize = 0;
 	if (MIDI_NotifyClient(wDevID, MOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
 		dprintf_midi(stddeb,"Linux 'modClose' // can't notify client !\n");
 		return MMSYSERR_INVALPARAM;
@@ -1120,16 +1140,16 @@
 static DWORD modData(WORD wDevID, DWORD dwParam)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	WORD	event;
+
 	dprintf_midi(stddeb,	
 		"modData(%04X, %08lX);\n", wDevID, dwParam);
-	if (MidiOutDev[index].unixdev == 0) {
+	if (MidiOutDev[wDevID].unixdev == 0) {
         dprintf_midi(stddeb,"Linux 'modData' // can't play !\n");
 		return MIDIERR_NODEVICE;
 		}
 	event = LOWORD(dwParam);
-	if (write (MidiOutDev[index].unixdev, 
+	if (write (MidiOutDev[wDevID].unixdev, 
 		&event, sizeof(WORD)) != sizeof(WORD)) {
 		dprintf_midi(stddeb,
 			"modData() // error writting unixdev !\n");
@@ -1146,12 +1166,13 @@
 static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	int		count;
 	LPWORD	ptr;
+	int     en;
+
 	dprintf_midi(stddeb,	
 		"modLongData(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
-	if (MidiOutDev[index].unixdev == 0) {
+	if (MidiOutDev[wDevID].unixdev == 0) {
         dprintf_midi(stddeb,"Linux 'modLongData' // can't play !\n");
 		return MIDIERR_NODEVICE;
 		}
@@ -1162,20 +1183,30 @@
 	lpMidiHdr->dwFlags |= MHDR_INQUEUE;
 	dprintf_midi(stddeb,
 		"modLongData() // dwBytesRecorded %lu !\n", lpMidiHdr->dwBytesRecorded);
+	dprintf_midi(stddeb,
+                "                 %02X %02X %02X %02X\n",lpMidiHdr->lpData[0],
+                                                         lpMidiHdr->lpData[1],
+		                                         lpMidiHdr->lpData[2],
+		                                         lpMidiHdr->lpData[3]);
 /*
-	count = write (MidiOutDev[index].unixdev, 
+	count = write (MidiOutDev[wDevID].unixdev, 
 		lpMidiHdr->lpData, lpMidiHdr->dwBytesRecorded);
 */
 	ptr = (LPWORD)lpMidiHdr->lpData;
 	for (count = 0; count < lpMidiHdr->dwBytesRecorded; count++) {
-		if (write (MidiOutDev[index].unixdev, ptr, 
+		if (write (MidiOutDev[wDevID].unixdev, ptr, 
 			sizeof(WORD)) != sizeof(WORD)) break;
 		ptr++;
 		}
+
+	en = errno;
+	dprintf_midi(stddeb, "Linux 'modLongData' // after write count = %d\n",count);
 	if (count != lpMidiHdr->dwBytesRecorded) {
 		dprintf_midi(stddeb,
 			"modLongData() // error writting unixdev #%d ! (%d != %ld)\n",
-			MidiOutDev[index].unixdev, count, lpMidiHdr->dwBytesRecorded);
+			MidiOutDev[wDevID].unixdev, count, lpMidiHdr->dwBytesRecorded);
+		dprintf_midi(stddeb,
+			"                 errno = %d error = %s\n",en,strerror(en));
 		return MMSYSERR_NOTENABLED;
 		}
 	lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
@@ -1196,19 +1227,18 @@
 static DWORD modPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_midi(stddeb,
 		  "modPrepare(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
-	if (MidiOutDev[index].unixdev == 0) {
+	if (MidiOutDev[wDevID].unixdev == 0) {
 		dprintf_midi(stddeb,"Linux 'modPrepare' // can't prepare !\n");
 		return MMSYSERR_NOTENABLED;
 		}
-	if (MidiOutDev[index].lpQueueHdr != NULL) {
+	if (MidiOutDev[wDevID].lpQueueHdr != NULL) {
 		dprintf_midi(stddeb,"Linux 'modPrepare' // already prepare !\n");
 		return MMSYSERR_NOTENABLED;
 		}
-	MidiOutDev[index].dwTotalPlayed = 0;
-	MidiOutDev[index].lpQueueHdr = lpMidiHdr;
+	MidiOutDev[wDevID].dwTotalPlayed = 0;
+	MidiOutDev[wDevID].lpQueueHdr = PTR_SEG_TO_LIN(lpMidiHdr);
 	if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
 	lpMidiHdr->dwFlags |= MHDR_PREPARED;
 	lpMidiHdr->dwFlags &= ~MHDR_DONE;
@@ -1224,10 +1254,9 @@
 static DWORD modUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
 {
 #if defined(linux) || defined(__FreeBSD__)
-	int index = MMSYSTEM_DevIDToIndex(wDevID);
 	dprintf_midi(stddeb,
 		"modUnprepare(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
-	if (MidiOutDev[index].unixdev == 0) {
+	if (MidiOutDev[wDevID].unixdev == 0) {
 		dprintf_midi(stddeb,"Linux 'modUnprepare' // can't unprepare !\n");
 		return MMSYSERR_NOTENABLED;
 		}
diff --git a/multimedia/mmaux.c b/multimedia/mmaux.c
index 470c78d..5b261d0 100644
--- a/multimedia/mmaux.c
+++ b/multimedia/mmaux.c
@@ -18,9 +18,12 @@
 
 #ifdef linux
 #include <linux/soundcard.h>
+#elif __FreeBSD__
+#include <machine/soundcard.h>
 #endif
 
-int MMSYSTEM_DevIDToIndex(UINT16);
+#include "stddebug.h"
+#include "debug.h"
 
 #define SOUND_DEV "/dev/dsp"
 #define MIXER_DEV "/dev/mixer"
@@ -45,15 +48,15 @@
 #ifdef linux
 	int 	mixer;
 	int		volume;
-	printf("AUX_GetDevCaps(%04X, %p, %lu);\n", wDevID, lpCaps, dwSize);
+	dprintf_mmaux(stddeb,"AUX_GetDevCaps(%04X, %p, %lu);\n", wDevID, lpCaps, dwSize);
 	if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
 	if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) {
-		printf("AUX_GetDevCaps // mixer device not available !\n");
+		dprintf_mmaux(stddeb,"AUX_GetDevCaps // mixer device not available !\n");
 		return MMSYSERR_NOTENABLED;
 		}
     if (ioctl(mixer, SOUND_MIXER_READ_LINE, &volume) == -1) {
 		close(mixer);
-		printf("AUX_GetDevCaps // unable read mixer !\n");
+		dprintf_mmaux(stddeb,"AUX_GetDevCaps // unable read mixer !\n");
 		return MMSYSERR_NOTENABLED;
 		}
 	close(mixer);
@@ -61,7 +64,7 @@
 	lpCaps->wMid = 0x0002;
 	lpCaps->vDriverVersion = 0x0200;
 	lpCaps->dwSupport = AUXCAPS_VOLUME | AUXCAPS_LRVOLUME;
-	switch (MMSYSTEM_DevIDToIndex(wDevID)) {
+	switch (wDevID) {
 		case 0:
 			lpCaps->wPid = 0x0196;
 			strcpy(lpCaps->szPname, "SB16 Aux: Wave");
@@ -117,49 +120,50 @@
 	int 	mixer;
 	int		volume, left, right;
 	int		cmd;
-	printf("AUX_GetVolume(%04X, %p);\n", wDevID, lpdwVol);
+
+	dprintf_mmaux(stddeb,"AUX_GetVolume(%04X, %p);\n", wDevID, lpdwVol);
 	if (lpdwVol == NULL) return MMSYSERR_NOTENABLED;
 	if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) {
-		printf("Linux 'AUX_GetVolume' // mixer device not available !\n");
+		dprintf_mmaux(stddeb,"Linux 'AUX_GetVolume' // mixer device not available !\n");
 		return MMSYSERR_NOTENABLED;
 		}
-	switch(MMSYSTEM_DevIDToIndex(wDevID)) {
+	switch(wDevID) {
 		case 0:
-			printf("Linux 'AUX_GetVolume' // SOUND_MIXER_READ_PCM !\n");
+			dprintf_mmaux(stddeb,"Linux 'AUX_GetVolume' // SOUND_MIXER_READ_PCM !\n");
 			cmd = SOUND_MIXER_READ_PCM;
 			break;
 		case 1:
-			printf("Linux 'AUX_GetVolume' // SOUND_MIXER_READ_SYNTH !\n");
+			dprintf_mmaux(stddeb,"Linux 'AUX_GetVolume' // SOUND_MIXER_READ_SYNTH !\n");
 			cmd = SOUND_MIXER_READ_SYNTH;
 			break;
 		case 2:
-			printf("Linux 'AUX_GetVolume' // SOUND_MIXER_READ_CD !\n");
+			dprintf_mmaux(stddeb,"Linux 'AUX_GetVolume' // SOUND_MIXER_READ_CD !\n");
 			cmd = SOUND_MIXER_READ_CD;
 			break;
 		case 3:
-			printf("Linux 'AUX_GetVolume' // SOUND_MIXER_READ_LINE !\n");
+			dprintf_mmaux(stddeb,"Linux 'AUX_GetVolume' // SOUND_MIXER_READ_LINE !\n");
 			cmd = SOUND_MIXER_READ_LINE;
 			break;
 		case 4:
-			printf("Linux 'AUX_GetVolume' // SOUND_MIXER_READ_MIC !\n");
+			dprintf_mmaux(stddeb,"Linux 'AUX_GetVolume' // SOUND_MIXER_READ_MIC !\n");
 			cmd = SOUND_MIXER_READ_MIC;
 			break;
 		case 5:
-			printf("Linux 'AUX_GetVolume' // SOUND_MIXER_READ_VOLUME !\n");
+			dprintf_mmaux(stddeb,"Linux 'AUX_GetVolume' // SOUND_MIXER_READ_VOLUME !\n");
 			cmd = SOUND_MIXER_READ_VOLUME;
 			break;
 		default:
-			fprintf(stderr, "Linux 'AUX_GetVolume' // invalid device id=%04X !\n", wDevID);
+			dprintf_mmaux(stddeb, "Linux 'AUX_GetVolume' // invalid device id=%04X !\n", wDevID);
 			return MMSYSERR_NOTENABLED;
 		}
 	if (ioctl(mixer, cmd, &volume) == -1) {
-		printf("Linux 'AUX_GetVolume' // unable read mixer !\n");
+		dprintf_mmaux(stddeb,"Linux 'AUX_GetVolume' // unable read mixer !\n");
 		return MMSYSERR_NOTENABLED;
 		}
 	close(mixer);
 	left = volume & 0x7F;
 	right = (volume >> 8) & 0x7F;
-	printf("Linux 'AUX_GetVolume' // left=%d right=%d !\n", left, right);
+	dprintf_mmaux(stddeb,"Linux 'AUX_GetVolume' // left=%d right=%d !\n", left, right);
 	*lpdwVol = MAKELONG(left << 9, right << 9);
 	return MMSYSERR_NOERROR;
 #else
@@ -176,44 +180,44 @@
 	int 	mixer;
 	int		volume;
 	int		cmd;
-	printf("AUX_SetVolume(%04X, %08lX);\n", wDevID, dwParam);
+	dprintf_mmaux(stddeb,"AUX_SetVolume(%04X, %08lX);\n", wDevID, dwParam);
 	volume = (LOWORD(dwParam) >> 9 & 0x7F) + 
 		((HIWORD(dwParam) >> 9  & 0x7F) << 8);
 	if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) {
-		printf("Linux 'AUX_SetVolume' // mixer device not available !\n");
+		dprintf_mmaux(stddeb,"Linux 'AUX_SetVolume' // mixer device not available !\n");
 		return MMSYSERR_NOTENABLED;
 		}
-	switch(MMSYSTEM_DevIDToIndex(wDevID)) {
+	switch(wDevID) {
 		case 0:
-			printf("Linux 'AUX_SetVolume' // SOUND_MIXER_WRITE_PCM !\n");
+			dprintf_mmaux(stddeb,"Linux 'AUX_SetVolume' // SOUND_MIXER_WRITE_PCM !\n");
 			cmd = SOUND_MIXER_WRITE_PCM;
 			break;
 		case 1:
-			printf("Linux 'AUX_SetVolume' // SOUND_MIXER_WRITE_SYNTH !\n");
+			dprintf_mmaux(stddeb,"Linux 'AUX_SetVolume' // SOUND_MIXER_WRITE_SYNTH !\n");
 			cmd = SOUND_MIXER_WRITE_SYNTH;
 			break;
 		case 2:
-			printf("Linux 'AUX_SetVolume' // SOUND_MIXER_WRITE_CD !\n");
+			dprintf_mmaux(stddeb,"Linux 'AUX_SetVolume' // SOUND_MIXER_WRITE_CD !\n");
 			cmd = SOUND_MIXER_WRITE_CD;
 			break;
 		case 3:
-			printf("Linux 'AUX_SetVolume' // SOUND_MIXER_WRITE_LINE !\n");
+			dprintf_mmaux(stddeb,"Linux 'AUX_SetVolume' // SOUND_MIXER_WRITE_LINE !\n");
 			cmd = SOUND_MIXER_WRITE_LINE;
 			break;
 		case 4:
-			printf("Linux 'AUX_SetVolume' // SOUND_MIXER_WRITE_MIC !\n");
+			dprintf_mmaux(stddeb,"Linux 'AUX_SetVolume' // SOUND_MIXER_WRITE_MIC !\n");
 			cmd = SOUND_MIXER_WRITE_MIC;
 			break;
 		case 5:
-			printf("Linux 'AUX_SetVolume' // SOUND_MIXER_WRITE_VOLUME !\n");
+			dprintf_mmaux(stddeb,"Linux 'AUX_SetVolume' // SOUND_MIXER_WRITE_VOLUME !\n");
 			cmd = SOUND_MIXER_WRITE_VOLUME;
 			break;
 		default:
-			fprintf(stderr, "Linux 'AUX_SetVolume' // invalid device id=%04X !\n", wDevID);
+			dprintf_mmaux(stddeb, "Linux 'AUX_SetVolume' // invalid device id=%04X !\n", wDevID);
 			return MMSYSERR_NOTENABLED;
 		}
     if (ioctl(mixer, cmd, &volume) == -1) {
-		printf("Linux 'AUX_SetVolume' // unable set mixer !\n");
+		dprintf_mmaux(stddeb,"Linux 'AUX_SetVolume' // unable set mixer !\n");
 		return MMSYSERR_NOTENABLED;
 		}
 	close(mixer);
@@ -230,21 +234,21 @@
 DWORD auxMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
 					DWORD dwParam1, DWORD dwParam2)
 {
-	printf("auxMessage(%04X, %04X, %08lX, %08lX, %08lX);\n", 
+	dprintf_mmaux(stddeb,"auxMessage(%04X, %04X, %08lX, %08lX, %08lX);\n", 
 			wDevID, wMsg, dwUser, dwParam1, dwParam2);
 	switch(wMsg) {
 		case AUXDM_GETDEVCAPS:
 			return AUX_GetDevCaps(wDevID, 
 				(LPAUXCAPS)PTR_SEG_TO_LIN(dwParam1), dwParam2);
 		case AUXDM_GETNUMDEVS:
-			printf("AUX_GetNumDevs() return %d;\n", NumDev);
+			dprintf_mmaux(stddeb,"AUX_GetNumDevs() return %d;\n", NumDev);
 			return NumDev;
 		case AUXDM_GETVOLUME:
 			return AUX_GetVolume(wDevID, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
 		case AUXDM_SETVOLUME:
 			return AUX_SetVolume(wDevID, dwParam1);
 		default:
-			fprintf(stderr,"auxMessage // unknown message !\n");
+			dprintf_mmaux(stddeb,"auxMessage // unknown message !\n");
 		}
 	return MMSYSERR_NOTSUPPORTED;
 }
diff --git a/multimedia/mmsystem.c b/multimedia/mmsystem.c
index 10da700..10d780d 100644
--- a/multimedia/mmsystem.c
+++ b/multimedia/mmsystem.c
@@ -188,7 +188,7 @@
 			    lpWaveDesc->hWave    = 0;
 			    lpWaveDesc->lpFormat = (LPWAVEFORMAT) SEGPTR_GET(lpFormat);
 
-			    dwRet = wodMessage( MMSYSTEM_FirstDevID(), 
+			    dwRet = wodMessage( 0, 
 						WODM_OPEN, 0, (DWORD)SEGPTR_GET(lpWaveDesc), CALLBACK_NULL);
 			    SEGPTR_FREE(lpFormat);
 			    SEGPTR_FREE(lpWaveDesc);
@@ -208,7 +208,7 @@
 				lpWaveHdr->dwFlags = 0L;
 				lpWaveHdr->dwLoops = 0L;
 
-				dwRet = wodMessage( MMSYSTEM_FirstDevID(),
+				dwRet = wodMessage( 0,
 						    WODM_PREPARE, 0, (DWORD)spWaveHdr, sizeof(WAVEHDR));
 				if (dwRet == MMSYSERR_NOERROR) 
 				{
@@ -218,12 +218,12 @@
 					if (count < 1) break;
 					lpWaveHdr->dwBufferLength = count;
 				/*	lpWaveHdr->dwBytesRecorded = count; */
-					wodMessage( MMSYSTEM_FirstDevID(), WODM_WRITE, 
+					wodMessage( 0, WODM_WRITE, 
 						    0, (DWORD)spWaveHdr, sizeof(WAVEHDR));
 				    }
-				    wodMessage( MMSYSTEM_FirstDevID(), 
-						WODM_UNPREPARE, 0, (DWORD)spWaveHdr, sizeof(WAVEHDR));
-				    wodMessage( MMSYSTEM_FirstDevID(),
+				    wodMessage( 0, 
+					        WODM_UNPREPARE, 0, (DWORD)spWaveHdr, sizeof(WAVEHDR));
+				    wodMessage( 0,
 						WODM_CLOSE, 0, 0L, 0L);
 
 				    bRet = TRUE;
@@ -547,17 +547,32 @@
 		case MCIERR_FILE_WRITE:
 			msgptr = "Cannot write to the specified file. Make sure you have enough disk space or are still connected to the network.";
 			break;
+		case MCIERR_SEQ_DIV_INCOMPATIBLE:
+			msgptr = "The time formats of the \"song pointer\" and SMPTE are mutually exclusive. You can't use them together.";
+			break;
+		case MCIERR_SEQ_NOMIDIPRESENT:
+			msgptr = "The system has no installed MIDI devices. Use the Drivers option from the Control Panel to install a MIDI driver.";
+			break;
+		case MCIERR_SEQ_PORT_INUSE:
+			msgptr = "The specified MIDI port is already in use. Wait until it is free; the try again.";
+			break;
+		case MCIERR_SEQ_PORT_MAPNODEVICE:
+			msgptr = "The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use the MIDI Mapper option from the Control Panel to edit the setup.";
+			break;
+		case MCIERR_SEQ_PORT_MISCERROR:
+			msgptr = "An error occurred with the specified port.";
+			break;
+		case MCIERR_SEQ_PORT_NONEXISTENT:
+			msgptr = "The specified MIDI device is not installed on the system. Use the Drivers option from the Control Panel to install a MIDI device.";
+			break;
+		case MCIERR_SEQ_PORTUNSPECIFIED:
+			msgptr = "The system doesnot have a current MIDI port specified.";
+			break;
+		case MCIERR_SEQ_TIMER:
+			msgptr = "All multimedia timers are being used by other applications. Quit one of these applications; then, try again.";
+			break;
 
 /* 
-#define MCIERR_SEQ_DIV_INCOMPATIBLE     (MCIERR_BASE + 80)
-#define MCIERR_SEQ_PORT_INUSE           (MCIERR_BASE + 81)
-#define MCIERR_SEQ_PORT_NONEXISTENT     (MCIERR_BASE + 82)
-#define MCIERR_SEQ_PORT_MAPNODEVICE     (MCIERR_BASE + 83)
-#define MCIERR_SEQ_PORT_MISCERROR       (MCIERR_BASE + 84)
-#define MCIERR_SEQ_TIMER                (MCIERR_BASE + 85)
-#define MCIERR_SEQ_PORTUNSPECIFIED      (MCIERR_BASE + 86)
-#define MCIERR_SEQ_NOMIDIPRESENT        (MCIERR_BASE + 87)
-
 msg# 513 : vcr
 msg# 514 : videodisc
 msg# 515 : overlay
@@ -595,6 +610,7 @@
 			break;
 		}
         lstrcpyn32A(lpstrBuffer, msgptr, uLength);
+	dprintf_mmsys(stddeb, "mciGetErrorString // msg = %s;\n", msgptr);
 	return TRUE;
 }
 
@@ -608,7 +624,7 @@
 	if (!IsWindow32(hWndCallBack)) return FALSE;
 	dprintf_mmsys(stddeb, "mciDriverNotify // before PostMessage\n");
 	PostMessage16( hWndCallBack, MM_MCINOTIFY, wStatus, 
-                       MAKELONG(GetDrv(wDevID)->wDeviceID, 0));
+                       MAKELONG(wDevID, 0));
 	return TRUE;
 }
 
@@ -622,10 +638,12 @@
 	LPMCI_OPEN_PARMS lpParms;
 	UINT16	uDevTyp = 0;
 	UINT16	wDevID = MMSYSTEM_FirstDevID();
+	DWORD dwret;
 
 	lpParms = PTR_SEG_TO_LIN(lp16Parms);
 	dprintf_mmsys(stddeb, "mciOpen(%08lX, %p (%p))\n", dwParam, lp16Parms, lpParms);
 	if (lp16Parms == NULL) return MCIERR_INTERNAL;
+
 	while(GetDrv(wDevID)->wType != 0) {
 		wDevID = MMSYSTEM_NextDevID(wDevID);
 		if (!MMSYSTEM_DevIDValid(wDevID)) {
@@ -647,6 +665,7 @@
 		if (t) {
 			GetProfileString32A("mci extensions",t+1,"*",str,sizeof(str));
 			CharUpper32A(str);
+			dprintf_mmsys(stddeb, "mciOpen // str = %s \n", str);
 			if (strcmp(str, "CDAUDIO") == 0) {
 				uDevTyp = MCI_DEVTYPE_CD_AUDIO;
 			} else
@@ -710,32 +729,41 @@
 		}
 	}
 	GetDrv(wDevID)->wType = uDevTyp;
-	GetDrv(wDevID)->wDeviceID = wDevID;
+	GetDrv(wDevID)->wDeviceID = 0;  /* FIXME? for multiple devices */
 	lpParms->wDeviceID = wDevID;
 	dprintf_mmsys(stddeb, "MCI_OPEN // mcidev=%d, uDevTyp=%04X wDeviceID=%04X !\n", 
 				wDevID, uDevTyp, lpParms->wDeviceID);
 	switch(uDevTyp)
         {
         case MCI_DEVTYPE_CD_AUDIO:
-            return CDAUDIO_DriverProc( 0, 0, MCI_OPEN_DRIVER,
-                                       dwParam, (DWORD)lp16Parms);
+	  dwret = CDAUDIO_DriverProc( 0, 0, MCI_OPEN_DRIVER,
+				     dwParam, (DWORD)lp16Parms);
+	  break;
         case MCI_DEVTYPE_WAVEFORM_AUDIO:
-            return WAVE_DriverProc( 0, 0, MCI_OPEN_DRIVER, 
-                                    dwParam, (DWORD)lp16Parms);
+	  dwret =  WAVE_DriverProc( 0, 0, MCI_OPEN_DRIVER, 
+				   dwParam, (DWORD)lp16Parms);
+	  break;
         case MCI_DEVTYPE_SEQUENCER:
-            return MIDI_DriverProc( 0, 0, MCI_OPEN_DRIVER, 
-                                    dwParam, (DWORD)lp16Parms);
+	  dwret = MIDI_DriverProc( 0, 0, MCI_OPEN_DRIVER, 
+				  dwParam, (DWORD)lp16Parms);
+	  break;
         case MCI_DEVTYPE_ANIMATION:
-            return ANIM_DriverProc( 0, 0, MCI_OPEN_DRIVER, 
-                                    dwParam, (DWORD)lp16Parms);
+	  dwret = ANIM_DriverProc( 0, 0, MCI_OPEN_DRIVER, 
+				  dwParam, (DWORD)lp16Parms);
+	  break;
         case MCI_DEVTYPE_DIGITAL_VIDEO:
-            dprintf_mmsys(stddeb, "MCI_OPEN // No DIGITAL_VIDEO yet !\n");
-            return MCIERR_DEVICE_NOT_INSTALLED;
+	  dprintf_mmsys(stddeb, "MCI_OPEN // No DIGITAL_VIDEO yet !\n");
+	  return MCIERR_DEVICE_NOT_INSTALLED;
         default:
-            dprintf_mmsys(stddeb, "MCI_OPEN // Invalid Device Name '%08lx' !\n", lpParms->lpstrDeviceType);
-            return MCIERR_INVALID_DEVICE_NAME;
+	  dprintf_mmsys(stddeb, "MCI_OPEN // Invalid Device Name '%08lx' !\n", lpParms->lpstrDeviceType);
+	  return MCIERR_INVALID_DEVICE_NAME;
         }
-	return MCIERR_INTERNAL;
+
+	/* only handled devices fall through */
+	dprintf_mmsys(stddeb, "MCI_OPEN // wDevID = %04X wDeviceID = %d dwret = %ld\n",wDevID, lpParms->wDeviceID, dwret);
+	return dwret;
+
+/*	return MCIERR_INTERNAL; */
 }
 
 
@@ -745,7 +773,8 @@
 DWORD mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
 {
 	DWORD	dwRet = MCIERR_INTERNAL;
-	dprintf_mmsys(stddeb, "mciClose(%u, %08lX, %p)\n", wDevID, dwParam, lpParms);
+
+	dprintf_mmsys(stddeb, "mciClose(%04x, %08lX, %p)\n", wDevID, dwParam, lpParms);
 	switch(GetDrv(wDevID)->wType) {
 		case MCI_DEVTYPE_CD_AUDIO:
 			dwRet = CDAUDIO_DriverProc(GetDrv(wDevID)->wDeviceID,0,
@@ -768,14 +797,16 @@
 			break;
 		default:
 			dprintf_mmsys(stddeb, "mciClose() // unknown device type=%04X !\n", GetDrv(wDevID)->wType);
+			dwRet = MCIERR_DEVICE_NOT_INSTALLED;
 		}
 	GetDrv(wDevID)->wType = 0;
+	dprintf_mmsys(stddeb, "mciClose() // returns %ld\n",dwRet);
 	return dwRet;
 }
 
 
 /**************************************************************************
-* 				mciSound				[internal]
+* 				mciSysinfo				[internal]
 */
 DWORD mciSysInfo(DWORD dwFlags, LPMCI_SYSINFO_PARMS lpParms)
 {
@@ -936,7 +967,7 @@
 	return 0;
 
     wDevID = MMSYSTEM_FirstDevID();
-    while(GetDrv(wDevID)->wType) {
+    while(MMSYSTEM_DevIDValid(wDevID) && GetDrv(wDevID)->wType) {
 	if (GetOpenDrv(wDevID)->lpstrDeviceType && 
             strcmp(PTR_SEG_TO_LIN(GetOpenDrv(wDevID)->lpstrDeviceType), lpstrName) == 0)
 	    return wDevID;
@@ -1524,6 +1555,7 @@
 	LPWAVEOPENDESC	lp16Desc;
 	DWORD	dwRet = 0;
 	BOOL32	bMapperFlg = FALSE;
+
 	dprintf_mmsys(stddeb, "waveOutOpen(%p, %d, %p, %08lX, %08lX, %08lX);\n", 
 		lphWaveOut, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
 	if (dwFlags & WAVE_FORMAT_QUERY) {
@@ -1535,13 +1567,14 @@
 		uDeviceID = 0;
 		}
 	if (lpFormat == NULL) return WAVERR_BADFORMAT;
+
 	hWaveOut = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
 	if (lphWaveOut != NULL) *lphWaveOut = hWaveOut;
 	lp16Desc = (LPWAVEOPENDESC) USER_HEAP_SEG_ADDR(hWaveOut);
 	lpDesc = (LPWAVEOPENDESC) PTR_SEG_TO_LIN(lp16Desc);
 	if (lpDesc == NULL) return MMSYSERR_NOMEM;
 	lpDesc->hWave = hWaveOut;
-	lpDesc->lpFormat = lpFormat;
+	lpDesc->lpFormat = lpFormat;  /* should the struct be copied iso pointer? */
 	lpDesc->dwCallBack = dwCallback;
 	lpDesc->dwInstance = dwInstance;
 	while(uDeviceID < MAXWAVEDRIVERS) {
@@ -1556,6 +1589,7 @@
 		dprintf_mmsys(stddeb, "waveOutOpen	// End of WAVE_FORMAT_QUERY !\n");
 		waveOutClose(hWaveOut);
 		}
+	lpDesc->uDeviceID = uDeviceID;  /* save physical Device ID */
 	return dwRet;
 }
 
@@ -1565,10 +1599,11 @@
 UINT16 waveOutClose(HWAVEOUT16 hWaveOut)
 {
 	LPWAVEOPENDESC	lpDesc;
+
 	dprintf_mmsys(stddeb, "waveOutClose(%04X)\n", hWaveOut);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return wodMessage( MMSYSTEM_FirstDevID(), WODM_CLOSE, lpDesc->dwInstance, 0L, 0L);
+	return wodMessage( lpDesc->uDeviceID, WODM_CLOSE, lpDesc->dwInstance, 0L, 0L);
 }
 
 /**************************************************************************
@@ -1578,11 +1613,12 @@
      WAVEHDR * lpWaveOutHdr, UINT16 uSize)
 {
 	LPWAVEOPENDESC	lpDesc;
+
 	dprintf_mmsys(stddeb, "waveOutPrepareHeader(%04X, %p, %u);\n", 
 					hWaveOut, lpWaveOutHdr, uSize);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return wodMessage( MMSYSTEM_FirstDevID(), WODM_PREPARE, lpDesc->dwInstance, 
+	return wodMessage( lpDesc->uDeviceID, WODM_PREPARE, lpDesc->dwInstance, 
 							(DWORD)lpWaveOutHdr, uSize);
 }
 
@@ -1593,11 +1629,12 @@
     WAVEHDR * lpWaveOutHdr, UINT16 uSize)
 {
 	LPWAVEOPENDESC	lpDesc;
+
 	dprintf_mmsys(stddeb, "waveOutUnprepareHeader(%04X, %p, %u);\n", 
 						hWaveOut, lpWaveOutHdr, uSize);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return wodMessage( MMSYSTEM_FirstDevID(), WODM_UNPREPARE, lpDesc->dwInstance, 
+	return wodMessage( lpDesc->uDeviceID, WODM_UNPREPARE, lpDesc->dwInstance, 
 							(DWORD)lpWaveOutHdr, uSize);
 }
 
@@ -1607,10 +1644,11 @@
 UINT16 waveOutWrite(HWAVEOUT16 hWaveOut, WAVEHDR * lpWaveOutHdr,  UINT16 uSize)
 {
 	LPWAVEOPENDESC	lpDesc;
+
 	dprintf_mmsys(stddeb, "waveOutWrite(%04X, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return wodMessage( MMSYSTEM_FirstDevID(), WODM_WRITE, lpDesc->dwInstance, 
+	return wodMessage( lpDesc->uDeviceID, WODM_WRITE, lpDesc->dwInstance, 
 							(DWORD)lpWaveOutHdr, uSize);
 }
 
@@ -1620,10 +1658,11 @@
 UINT16 waveOutPause(HWAVEOUT16 hWaveOut)
 {
 	LPWAVEOPENDESC	lpDesc;
+
 	dprintf_mmsys(stddeb, "waveOutPause(%04X)\n", hWaveOut);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return wodMessage( MMSYSTEM_FirstDevID(), WODM_PAUSE, lpDesc->dwInstance, 0L, 0L);
+	return wodMessage( lpDesc->uDeviceID, WODM_PAUSE, lpDesc->dwInstance, 0L, 0L);
 }
 
 /**************************************************************************
@@ -1632,10 +1671,11 @@
 UINT16 waveOutRestart(HWAVEOUT16 hWaveOut)
 {
 	LPWAVEOPENDESC	lpDesc;
+
 	dprintf_mmsys(stddeb, "waveOutRestart(%04X)\n", hWaveOut);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return wodMessage( MMSYSTEM_FirstDevID(), WODM_RESTART, lpDesc->dwInstance, 0L, 0L);
+	return wodMessage( lpDesc->uDeviceID, WODM_RESTART, lpDesc->dwInstance, 0L, 0L);
 }
 
 /**************************************************************************
@@ -1647,7 +1687,7 @@
 	dprintf_mmsys(stddeb, "waveOutReset(%04X)\n", hWaveOut);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return wodMessage( MMSYSTEM_FirstDevID(), WODM_RESET, lpDesc->dwInstance, 0L, 0L);
+	return wodMessage( lpDesc->uDeviceID, WODM_RESET, lpDesc->dwInstance, 0L, 0L);
 }
 
 /**************************************************************************
@@ -1659,7 +1699,7 @@
 	dprintf_mmsys(stddeb, "waveOutGetPosition(%04X, %p, %u);\n", hWaveOut, lpTime, uSize);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return wodMessage( MMSYSTEM_FirstDevID(), WODM_GETPOS, lpDesc->dwInstance, 
+	return wodMessage( lpDesc->uDeviceID, WODM_GETPOS, lpDesc->dwInstance, 
 							(DWORD)lpTime, (DWORD)uSize);
 }
 
@@ -1672,7 +1712,7 @@
 	dprintf_mmsys(stddeb, "waveOutGetPitch(%04X, %p);\n", hWaveOut, lpdwPitch);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return wodMessage( MMSYSTEM_FirstDevID(), WODM_GETPITCH, lpDesc->dwInstance, 
+	return wodMessage( lpDesc->uDeviceID, WODM_GETPITCH, lpDesc->dwInstance, 
 								(DWORD)lpdwPitch, 0L);
 }
 
@@ -1685,7 +1725,7 @@
 	dprintf_mmsys(stddeb, "waveOutSetPitch(%04X, %08lX);\n", hWaveOut, dwPitch);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return wodMessage( MMSYSTEM_FirstDevID(), WODM_SETPITCH, lpDesc->dwInstance, (DWORD)dwPitch, 0L);
+	return wodMessage( lpDesc->uDeviceID, WODM_SETPITCH, lpDesc->dwInstance, (DWORD)dwPitch, 0L);
 }
 
 /**************************************************************************
@@ -1715,7 +1755,7 @@
 	dprintf_mmsys(stddeb, "waveOutGetPlaybackRate(%04X, %p);\n", hWaveOut, lpdwRate);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return wodMessage( MMSYSTEM_FirstDevID(), WODM_GETPLAYBACKRATE, lpDesc->dwInstance, 
+	return wodMessage( lpDesc->uDeviceID, WODM_GETPLAYBACKRATE, lpDesc->dwInstance, 
 								(DWORD)lpdwRate, 0L);
 }
 
@@ -1728,7 +1768,7 @@
 	dprintf_mmsys(stddeb, "waveOutSetPlaybackRate(%04X, %08lX);\n", hWaveOut, dwRate);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return wodMessage( MMSYSTEM_FirstDevID(), WODM_SETPLAYBACKRATE, 
+	return wodMessage( lpDesc->uDeviceID, WODM_SETPLAYBACKRATE, 
 		lpDesc->dwInstance, (DWORD)dwRate, 0L);
 }
 
@@ -1754,7 +1794,8 @@
 /*
 	*lpuDeviceID = lpParms->wDeviceID; 
 */
-	return 0;
+	*lpuDeviceID = lpDesc->uDeviceID;
+        return 0;
 }
 
 /**************************************************************************
@@ -1768,7 +1809,7 @@
 			hWaveOut, uMessage, dwParam1, dwParam2);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveOut);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return wodMessage( MMSYSTEM_FirstDevID(), uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
+	return wodMessage( lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
 }
 
 /**************************************************************************
@@ -1857,10 +1898,11 @@
 UINT16 waveInClose(HWAVEIN16 hWaveIn)
 {
 	LPWAVEOPENDESC	lpDesc;
+
 	dprintf_mmsys(stddeb, "waveInClose(%04X)\n", hWaveIn);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return widMessage(0, WIDM_CLOSE, lpDesc->dwInstance, 0L, 0L);
+	return widMessage(lpDesc->uDeviceID, WIDM_CLOSE, lpDesc->dwInstance, 0L, 0L);
 }
 
 
@@ -1872,6 +1914,7 @@
 {
 	LPWAVEOPENDESC	lpDesc;
 	LPWAVEHDR 		lp32WaveInHdr;
+
 	dprintf_mmsys(stddeb, "waveInPrepareHeader(%04X, %p, %u);\n", 
 					hWaveIn, lpWaveInHdr, uSize);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
@@ -1882,7 +1925,7 @@
     lp32WaveInHdr->dwBytesRecorded = 0;
 	dprintf_mmsys(stddeb, "waveInPrepareHeader // lpData=%p size=%lu \n", 
 		lp32WaveInHdr->lpData, lp32WaveInHdr->dwBufferLength);
-	return widMessage(0, WIDM_PREPARE, lpDesc->dwInstance, 
+	return widMessage(lpDesc->uDeviceID, WIDM_PREPARE, lpDesc->dwInstance, 
 							(DWORD)lpWaveInHdr, uSize);
 }
 
@@ -1895,6 +1938,7 @@
 {
 	LPWAVEOPENDESC	lpDesc;
 	LPWAVEHDR 		lp32WaveInHdr;
+
 	dprintf_mmsys(stddeb, "waveInUnprepareHeader(%04X, %p, %u);\n", 
 						hWaveIn, lpWaveInHdr, uSize);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
@@ -1904,7 +1948,7 @@
 	USER_HEAP_FREE(HIWORD((DWORD)lp32WaveInHdr->lpData));
 	lp32WaveInHdr->lpData = NULL;
 	lp32WaveInHdr->lpNext = NULL;
-	return widMessage(0, WIDM_UNPREPARE, lpDesc->dwInstance, 
+	return widMessage(lpDesc->uDeviceID, WIDM_UNPREPARE, lpDesc->dwInstance, 
 							(DWORD)lpWaveInHdr, uSize);
 }
 
@@ -1917,6 +1961,7 @@
 {
 	LPWAVEOPENDESC	lpDesc;
 	LPWAVEHDR 		lp32WaveInHdr;
+
 	dprintf_mmsys(stddeb, "waveInAddBuffer(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
@@ -1926,7 +1971,7 @@
     lp32WaveInHdr->dwBytesRecorded = 0;
 	dprintf_mmsys(stddeb, "waveInAddBuffer // lpData=%p size=%lu \n", 
 		lp32WaveInHdr->lpData, lp32WaveInHdr->dwBufferLength);
-	return widMessage(0, WIDM_ADDBUFFER, lpDesc->dwInstance,
+	return widMessage(lpDesc->uDeviceID, WIDM_ADDBUFFER, lpDesc->dwInstance,
 								(DWORD)lpWaveInHdr, uSize);
 }
 
@@ -1937,10 +1982,11 @@
 UINT16 waveInStart(HWAVEIN16 hWaveIn)
 {
 	LPWAVEOPENDESC	lpDesc;
+
 	dprintf_mmsys(stddeb, "waveInStart(%04X)\n", hWaveIn);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return widMessage(0, WIDM_START, lpDesc->dwInstance, 0L, 0L);
+	return widMessage(lpDesc->uDeviceID, WIDM_START, lpDesc->dwInstance, 0L, 0L);
 }
 
 
@@ -1950,10 +1996,11 @@
 UINT16 waveInStop(HWAVEIN16 hWaveIn)
 {
 	LPWAVEOPENDESC	lpDesc;
+
 	dprintf_mmsys(stddeb, "waveInStop(%04X)\n", hWaveIn);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return widMessage(0, WIDM_STOP, lpDesc->dwInstance, 0L, 0L);
+	return widMessage(lpDesc->uDeviceID, WIDM_STOP, lpDesc->dwInstance, 0L, 0L);
 }
 
 
@@ -1963,10 +2010,11 @@
 UINT16 waveInReset(HWAVEIN16 hWaveIn)
 {
 	LPWAVEOPENDESC	lpDesc;
+
 	dprintf_mmsys(stddeb, "waveInReset(%04X)\n", hWaveIn);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return widMessage(0, WIDM_RESET, lpDesc->dwInstance, 0L, 0L);
+	return widMessage(lpDesc->uDeviceID, WIDM_RESET, lpDesc->dwInstance, 0L, 0L);
 }
 
 
@@ -1976,10 +2024,11 @@
 UINT16 waveInGetPosition(HWAVEIN16 hWaveIn, MMTIME * lpTime, UINT16 uSize)
 {
 	LPWAVEOPENDESC	lpDesc;
+
 	dprintf_mmsys(stddeb, "waveInGetPosition(%04X, %p, %u);\n", hWaveIn, lpTime, uSize);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return widMessage(0, WIDM_GETPOS, lpDesc->dwInstance,
+	return widMessage(lpDesc->uDeviceID, WIDM_GETPOS, lpDesc->dwInstance,
 			  (DWORD)lpTime, (DWORD)uSize);
 }
 
@@ -1989,8 +2038,13 @@
 */
 UINT16 waveInGetID(HWAVEIN16 hWaveIn, UINT16 * lpuDeviceID)
 {
+	LPWAVEOPENDESC	lpDesc;
+
 	dprintf_mmsys(stddeb, "waveInGetID\n");
-	if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
+	if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
+	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
+	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
+	*lpuDeviceID = lpDesc->uDeviceID;
 	return 0;
 }
 
@@ -2002,11 +2056,12 @@
 		    DWORD dwParam1, DWORD dwParam2)
 {
 	LPWAVEOPENDESC	lpDesc;
+
 	dprintf_mmsys(stddeb, "waveInMessage(%04X, %04X, %08lX, %08lX)\n", 
 			hWaveIn, uMessage, dwParam1, dwParam2);
 	lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hWaveIn);
 	if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
-	return widMessage(0, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
+	return widMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
 }
 
 
diff --git a/multimedia/time.c b/multimedia/time.c
index 56e4e45..f9fa0c5 100644
--- a/multimedia/time.c
+++ b/multimedia/time.c
@@ -86,7 +86,7 @@
 /**************************************************************************
  * 				StartMMTime			[internal]
  */
-void StartMMTime()
+static void StartMMTime()
 {
     if (!mmTimeStarted) {
 	mmTimeStarted = TRUE;
diff --git a/objects/bitmap.c b/objects/bitmap.c
index 52f3ef4..fdb59d2 100644
--- a/objects/bitmap.c
+++ b/objects/bitmap.c
@@ -201,7 +201,7 @@
 	return 0;
     }
 
-    widthbytes	= DIB_GetImageWidthBytesX11(bmp->bitmap.bmWidth,bmp->bitmap.bmBitsPixel);
+    widthbytes	= DIB_GetXImageWidthBytes(bmp->bitmap.bmWidth,bmp->bitmap.bmBitsPixel);
     tmpbuffer	= (LPBYTE)xmalloc(widthbytes*height);
     image = XCreateImage( display, DefaultVisualOfScreen(screen),
 		  bmp->bitmap.bmBitsPixel, ZPixmap, 0, tmpbuffer,
@@ -223,8 +223,10 @@
             *tbuf = 0;
             for (w=0;w<bmp->bitmap.bmWidth;w++)
             {
+                if ((w%8) == 0)
+                    *tbuf = 0;
                 *tbuf |= XGetPixel(image,w,h)<<(7-(w&7));
-                if ((w&7) == 7) *(++tbuf) = 0;
+                if ((w&7) == 7) ++tbuf;
             }
             tbuf += pad;
         }
@@ -348,7 +350,7 @@
     }
     sbuf = (LPBYTE)buffer;
 
-    widthbytes	= DIB_GetImageWidthBytesX11(bmp->bitmap.bmWidth,bmp->bitmap.bmBitsPixel);
+    widthbytes	= DIB_GetXImageWidthBytes(bmp->bitmap.bmWidth,bmp->bitmap.bmBitsPixel);
     tmpbuffer	= (LPBYTE)xmalloc(widthbytes*height);
     image = XCreateImage( display, DefaultVisualOfScreen(screen),
 		  bmp->bitmap.bmBitsPixel, ZPixmap, 0, tmpbuffer,
diff --git a/objects/color.c b/objects/color.c
index 943b1da..3442d91 100644
--- a/objects/color.c
+++ b/objects/color.c
@@ -40,6 +40,8 @@
     Colormap    colorMap;
     UINT16      size;
     UINT16      flags;
+    INT32	monoPlane;	 /* bit plane different for white and black pixels */
+    BOOL32	bWhiteOn;	 /* monoPlane bit is 1 for the white pixel */
 } CSPACE;
 
 static CSPACE cSpace = {0, 0, 0};
@@ -125,6 +127,12 @@
     return cSpace.colorMap;
 }
 
+BOOL32 COLOR_GetMonoPlane(INT32* plane)
+{
+    *plane = cSpace.monoPlane;
+    return (cSpace.flags & COLOR_WHITESET) ? TRUE : FALSE;
+}
+
 UINT16 COLOR_GetSystemPaletteSize(void)
 {
     return (cSpace.flags & COLOR_PRIVATE) ? cSpace.size : 256;
@@ -537,10 +545,6 @@
 
     memset(COLOR_freeList, 0, 256*sizeof(unsigned char));
 
-    /* calculate max palette size */
-
-    cSpace.size = visual->map_entries;
-
     if (cSpace.flags & COLOR_PRIVATE)
 	COLOR_BuildPrivateMap( &cSpace );
     else
@@ -610,10 +614,20 @@
  */
 HPALETTE16 COLOR_Init(void)
 {
+    int	mask, white, black;
+
     visual = DefaultVisual( display, DefaultScreen(display) );
 
     dprintf_palette(stddeb,"COLOR_Init: initializing palette manager...");
 
+    white = WhitePixelOfScreen( screen );
+    black = BlackPixelOfScreen( screen );
+    cSpace.monoPlane = 1;
+    for( mask = 1; !((white & mask)^(black & mask)); mask <<= 1 )
+	 cSpace.monoPlane++;
+    cSpace.flags = (white & mask) ? COLOR_WHITESET : 0;
+    cSpace.size = visual->map_entries;
+
     switch(visual->class)
     {
     case DirectColor:
@@ -624,18 +638,23 @@
 	{
 	    XSetWindowAttributes win_attr;
 
-	    cSpace.flags |= COLOR_PRIVATE;
 	    cSpace.colorMap = XCreateColormap( display, rootWindow,
 						 visual, AllocAll );
 	    if (cSpace.colorMap)
 	    {
-	       if( rootWindow != DefaultRootWindow(display) )
-	         {
+	        cSpace.flags |= (COLOR_PRIVATE | COLOR_WHITESET);
+
+		cSpace.monoPlane = 1;
+		for( white = cSpace.size - 1; !(white & 1); white >>= 1 )
+		     cSpace.monoPlane++;
+
+	        if( rootWindow != DefaultRootWindow(display) )
+	        {
 		    win_attr.colormap = cSpace.colorMap;
 		    XChangeWindowAttributes( display, rootWindow,
 					 CWColormap, &win_attr );
-		 }
-	       break;
+		}
+		break;
 	    }
 	}
 	cSpace.colorMap = DefaultColormapOfScreen( screen );
@@ -658,7 +677,8 @@
 	break;	
     }
 
-    dprintf_palette(stddeb," visual class %i\n", visual->class);
+    dprintf_palette(stddeb," visual class %i (%i)\n", 
+		    visual->class, cSpace.monoPlane);
 
     return COLOR_InitPalette();
 }
diff --git a/objects/cursoricon.c b/objects/cursoricon.c
index 7212085..e8a9537 100644
--- a/objects/cursoricon.c
+++ b/objects/cursoricon.c
@@ -7,6 +7,8 @@
 /*
  * Theory:
  *
+ * http://www.microsoft.com/win32dev/ui/icons.htm
+ *
  * Cursors and icons are stored in a global heap block, with the
  * following layout:
  *
@@ -33,7 +35,6 @@
 #include "win.h"
 #include "stddebug.h"
 #include "debug.h"
-#include "xmalloc.h"
 #include "task.h"
 
 extern UINT16 COLOR_GetSystemPaletteSize();
@@ -237,14 +238,15 @@
 HGLOBAL16 CURSORICON_LoadHandler( HGLOBAL16 handle, HINSTANCE16 hInstance,
                                   BOOL32 fCursor )
 {
-    HBITMAP32 hAndBits, hXorBits;
-    HDC32 hdc;
-    int size, sizeAnd, sizeXor;
-    POINT16 hotspot = { 0 ,0 };
+    static char* __loadhandlerStr = "CURSORICON_LoadHandler";
+
+    int sizeAnd, sizeXor;
+    HBITMAP32 hAndBits = 0, hXorBits = 0; /* error condition for later */
     BITMAPOBJ *bmpXor, *bmpAnd;
-    BITMAPINFO *bmi, *pInfo;
+    POINT16 hotspot = { 0 ,0 };
     CURSORICONINFO *info;
-    char *bits;
+    BITMAPINFO *bmi;
+    HDC32 hdc;
 
     if (fCursor)  /* If cursor, get the hotspot */
     {
@@ -254,87 +256,81 @@
     }
     else bmi = (BITMAPINFO *)LockResource16( handle );
 
-    /* Create a copy of the bitmap header */
+    /* Check bitmap header */
 
-    size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
-    /* Make sure we have room for the monochrome bitmap later on */
-    size = MAX( size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD) );
-    pInfo = (BITMAPINFO *)xmalloc( size );
-    memcpy( pInfo, bmi, size );
-
-    if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
+    if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
+	 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)  ||
+	  bmi->bmiHeader.biCompression != BI_RGB) )
     {
-        if (pInfo->bmiHeader.biCompression != BI_RGB)
-        {
-            fprintf(stderr,"Unknown size for compressed icon bitmap.\n");
-            free( pInfo );
-            return 0;
-        }
-        pInfo->bmiHeader.biHeight /= 2;
+          fprintf(stderr,"%s: invalid bitmap header.\n", __loadhandlerStr);
+          return 0;
     }
-    else if (pInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
+
+    if( (hdc = GetDC32( 0 )) )
     {
-        BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)pInfo;
-        core->bcHeight /= 2;
+	BITMAPINFO* pInfo;
+        INT32 size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
+
+        /* Make sure we have room for the monochrome bitmap later on.
+	 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
+	 * up to and including the biBitCount. In-memory icon resource 
+	 * format is as follows:
+	 *
+	 *   BITMAPINFOHEADER   icHeader  // DIB header
+	 *   RGBQUAD         icColors[]   // Color table
+  	 *   BYTE            icXOR[]      // DIB bits for XOR mask
+	 *   BYTE            icAND[]      // DIB bits for AND mask
+	 */
+
+    	if( (pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0, 
+			  MAX(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))) )
+	{	
+	    memcpy( pInfo, bmi, size );	
+	    pInfo->bmiHeader.biHeight /= 2;
+
+	    /* Create the XOR bitmap */
+
+	    hXorBits = CreateDIBitmap32( hdc, &pInfo->bmiHeader, CBM_INIT,
+                                    (char*)bmi + size, pInfo, DIB_RGB_COLORS );
+	    if( hXorBits )
+	    {
+		char* bits = (char *)bmi + size + bmi->bmiHeader.biHeight *
+				DIB_GetDIBWidthBytes(bmi->bmiHeader.biWidth,
+						     bmi->bmiHeader.biBitCount) / 2;
+
+		pInfo->bmiHeader.biBitCount = 1;
+	        if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
+	        {
+	            RGBQUAD *rgb = pInfo->bmiColors;
+
+	            pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
+	            rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
+	            rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
+	            rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
+	        }
+	        else
+	        {
+	            RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
+
+	            rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
+	            rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
+	        }
+
+	        /* Create the AND bitmap */
+
+	        hAndBits = CreateDIBitmap32( hdc, &pInfo->bmiHeader, CBM_INIT,
+	                                     bits, pInfo, DIB_RGB_COLORS );
+		if( !hAndBits ) DeleteObject32( hXorBits );
+	    }
+	    HeapFree( GetProcessHeap(), 0, pInfo ); 
+	}
+	ReleaseDC32( 0, hdc );
     }
-    else
+
+    if( !hXorBits || !hAndBits ) 
     {
-        fprintf( stderr, "CURSORICON_Load: Unknown bitmap length %ld!\n",
-                 pInfo->bmiHeader.biSize );
-        free( pInfo );
-        return 0;
-    }
-
-    /* Create the XOR bitmap */
-
-    if (!(hdc = GetDC32( 0 )))
-    {
-        free( pInfo );
-        return 0;
-    }
-
-    hXorBits = CreateDIBitmap32( hdc, &pInfo->bmiHeader, CBM_INIT,
-                                 (char*)bmi + size, pInfo, DIB_RGB_COLORS );
-    if (!hXorBits) {
-        free( pInfo );
-    	ReleaseDC32( 0, hdc );
-    	return 0;
-    }
-
-    /* Fix the bitmap header to load the monochrome mask */
-
-    if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
-    {
-        BITMAPINFOHEADER *bih = &pInfo->bmiHeader;
-        RGBQUAD *rgb = pInfo->bmiColors;
-        bits = (char *)bmi + size +
-            DIB_GetImageWidthBytes(bih->biWidth,bih->biBitCount)*bih->biHeight;
-        bih->biBitCount = 1;
-        bih->biClrUsed = bih->biClrImportant = 2;
-        rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
-        rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
-        rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
-    }
-    else
-    {
-        BITMAPCOREHEADER *bch = (BITMAPCOREHEADER *)pInfo;
-        RGBTRIPLE *rgb = (RGBTRIPLE *)(bch + 1);
-        bits = (char *)bmi + size +
-            DIB_GetImageWidthBytes(bch->bcWidth,bch->bcBitCount)*bch->bcHeight;
-        bch->bcBitCount = 1;
-        rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
-        rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
-    }
-
-    /* Create the AND bitmap */
-
-    hAndBits = CreateDIBitmap32( hdc, &pInfo->bmiHeader, CBM_INIT,
-                                 bits, pInfo, DIB_RGB_COLORS );
-    ReleaseDC32( 0, hdc );
-    if (!hAndBits) {
-        DeleteObject32( hXorBits );
-        free( pInfo );
-    	return 0;
+	fprintf(stderr,"%s: unable to create a bitmap.\n", __loadhandlerStr );
+	return 0;
     }
 
     /* Now create the CURSORICONINFO structure */
@@ -451,12 +447,12 @@
  HTASK16 	 hTask = GetCurrentTask();
  TDB*  		 pTask = (TDB *)GlobalLock16(hTask);
 
- if(hIcon)
+ if(hIcon && pTask)
     if (!(ptr = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
        if (ptr->bPlanes * ptr->bBitsPerPixel == 1)
            hRet = CURSORICON_Copy( pTask->hInstance, hIcon );
        else
-          {
+       {
            BYTE  pAndBits[128];
            BYTE  pXorBits[128];
 	   int   x, y, ix, iy, shift; 
@@ -471,8 +467,6 @@
            COLORREF       col;
            CURSORICONINFO cI;
 
-           if(!pTask) return 0;
-
            memset(pXorBits, 0, 128);
            cI.bBitsPerPixel = 1; cI.bPlanes = 1;
            cI.ptHotSpot.x = cI.ptHotSpot.y = 15;
@@ -519,7 +513,7 @@
                 hRet = CURSORICON_Copy( pTask->hInstance ,
                               CURSORICON_Load(0,MAKEINTRESOURCE(OCR_DRAGOBJECT),
                                          SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, 1, TRUE) );
-          }
+       }
 
  return hRet;
 }
@@ -1149,3 +1143,8 @@
       }
     return CURSORICON_LoadHandler( hResource, 0, FALSE);
 }
+
+/**********************************************************************
+ *          GetIconInfo		(USER32.241)
+ */
+
diff --git a/objects/dib.c b/objects/dib.c
index 0eb78f0..a951745 100644
--- a/objects/dib.c
+++ b/objects/dib.c
@@ -18,53 +18,51 @@
 
 extern void CLIPPING_UpdateGCRegion(DC* );
 
+static int	bitmapDepthTable[] = { 8, 1, 32, 16, 24, 15, 4, 0 };
+static int	ximageDepthTable[] = { 0, 0, 0,  0,  0,  0,  0 };
+
 /***********************************************************************
- *           DIB_GetImageWidthBytesX11
- *
- * Return the width of an X image in bytes
+ *           DIB_Init
  */
-int DIB_GetImageWidthBytesX11( int width, int depth )
+BOOL32 DIB_Init()
 {
-    int		wbits;
-    XImage	*testimage;
+    int		i;
+    XImage*	testimage;
 
-#define DEPTHCASE(depth) 						\
-    case depth: {							\
-	static int w##depth = 0;					\
-	if (! w##depth ) {						\
-	    testimage=XCreateImage(display,DefaultVisualOfScreen(screen),\
-		   depth,ZPixmap,0,NULL,1,1,32,20);			\
-	    w##depth = testimage->bits_per_pixel;			\
-	    XDestroyImage(testimage);					\
-	}								\
-	wbits = width*w##depth;						\
-	break;								\
-    }
-
-    switch(depth)
+    for( i = 0; bitmapDepthTable[i]; i++ )
     {
-    	DEPTHCASE(1);
-	DEPTHCASE(4);
-	DEPTHCASE(8);
-	DEPTHCASE(15);
-	DEPTHCASE(16);
-	DEPTHCASE(24);
-	DEPTHCASE(32);
-	default:
-        	fprintf(stderr, "DIB: unsupported depth %d.\n", depth );
-	/* assume 32 bits/pixel */
-	        wbits = width*32;
-		break;
+	 testimage = XCreateImage(display, DefaultVisualOfScreen(screen),
+			 bitmapDepthTable[i], ZPixmap, 0, NULL, 1, 1, 32, 20 );
+	 if( testimage ) ximageDepthTable[i] = testimage->bits_per_pixel;
+	 else return FALSE;
+	 XDestroyImage(testimage);
     }
-    return 4 * ((wbits+31)/32);
+    return TRUE;
 }
 
 /***********************************************************************
- *           DIB_GetImageWidthBytes
+ *           DIB_GetXImageWidthBytes
  *
  * Return the width of an X image in bytes
  */
-int DIB_GetImageWidthBytes( int width, int depth )
+int DIB_GetXImageWidthBytes( int width, int depth )
+{
+    int		i;
+
+    for( i = 0; bitmapDepthTable[i] ; i++ )
+	 if( bitmapDepthTable[i] == depth )
+	     return (4 * ((width * ximageDepthTable[i] + 31)/32));
+    fprintf(stderr, "DIB: unsupported depth %d.\n", depth );
+    return (4 * width);
+}
+
+/***********************************************************************
+ *           DIB_GetDIBWidthBytes
+ *
+ * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
+ * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/struc/src/str01.htm
+ */
+int DIB_GetDIBWidthBytes( int width, int depth )
 {
     int words;
 
@@ -90,7 +88,7 @@
 /***********************************************************************
  *           DIB_BitmapInfoSize
  *
- * Return the size of the bitmap info structure.
+ * Return the size of the bitmap info structure including color table.
  */
 int DIB_BitmapInfoSize( BITMAPINFO * info, WORD coloruse )
 {
@@ -791,6 +789,8 @@
 
 /***********************************************************************
  *           GetDIBits32    (GDI32.170)
+ *
+ * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/func/src/f30_14.htm
  */
 INT32 GetDIBits32( HDC32 hdc, HBITMAP32 hbitmap, UINT32 startscan,
                    UINT32 lines, LPSTR bits, BITMAPINFO * info,
@@ -864,7 +864,7 @@
 	switch( info->bmiHeader.biBitCount )
 	{
 	   case 8:
-		/* pad up to 32 bit (FIXME: not 16? ) */
+		/* pad up to 32 bit */
 		pad += (4 - (info->bmiHeader.biWidth & 3)) & 3;
 		for( y = yend - 1; (int)y >= (int)startscan; y-- )
 		{
@@ -953,8 +953,8 @@
 	info->bmiHeader.biPlanes = 1;
 	info->bmiHeader.biBitCount = bmp->bitmap.bmBitsPixel;
 	info->bmiHeader.biSizeImage = bmp->bitmap.bmHeight *
-                             DIB_GetImageWidthBytes( bmp->bitmap.bmWidth,
-                                                     bmp->bitmap.bmBitsPixel );
+                             DIB_GetDIBWidthBytes( bmp->bitmap.bmWidth,
+                                                   bmp->bitmap.bmBitsPixel );
 	info->bmiHeader.biCompression = 0;
     }
 
diff --git a/objects/gdiobj.c b/objects/gdiobj.c
index 4422ed8..89aad65 100644
--- a/objects/gdiobj.c
+++ b/objects/gdiobj.c
@@ -156,10 +156,12 @@
 {
     HPALETTE16 hpalette;
     extern BOOL32 X11DRV_Init(void);
+    extern BOOL32 DIB_Init(void);
 
     /* Initialize drivers */
 
     if (!X11DRV_Init()) return FALSE;
+    if (!DIB_Init()) return FALSE;
 
       /* Create default palette */
 
diff --git a/objects/metafile.c b/objects/metafile.c
index 402e0aa..5c5da99 100644
--- a/objects/metafile.c
+++ b/objects/metafile.c
@@ -607,30 +607,38 @@
     case META_EXTTEXTOUT:
       {
         LPINT16 dxx;
+	LPSTR sot; 
         DWORD len;
 
         s1 = mr->rdParam[2];                              /* String length */
         len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
-         + sizeof(UINT16) + sizeof(RECT16);
-        if (mr->rdSize == len / 2)
-          dxx = NULL;                                    /* No array present */
-        else if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
-          dxx = &mr->rdParam[8+(s1+1)/2];                /* start of array */
-        else {
-          fprintf(stderr,
-           "PlayMetaFileRecord ExtTextOut mr->rdSize = %08lx, count = %x\n",
-           mr->rdSize, s1);
-          dxx = NULL;
-        }
+	 + sizeof(UINT16) +  (mr->rdParam[3] ? sizeof(RECT16) : 0);  /* rec len without dx array */
+
+	sot= (LPSTR)&mr->rdParam[4];			/* start_of_text */
+	if (mr->rdParam[3])
+	   sot+=sizeof(RECT16);				/* there is a rectangle, so add offset */
+	 
+	if (mr->rdSize == len / 2)
+          dxx = NULL;                                   /* determine if array present */
+        else 
+	  if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
+            dxx = (LPINT16)(sot+(((s1+1)>>1)*2));	   
+          else 
+	  {
+           fprintf(stderr,
+	     "Please report: PlayMetaFile/ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
+		   len,s1,mr->rdSize,mr->rdParam[3]);
+           dxx = NULL; /* should't happen -- but if, we continue with NULL [for workaround] */
+          }
         ExtTextOut16( hdc, mr->rdParam[1],              /* X position */
 	                   mr->rdParam[0],              /* Y position */
 	                   mr->rdParam[3],              /* options */
-	                   (LPRECT16) &mr->rdParam[4],  /* rectangle */
-                           (char *)(mr->rdParam + 8),   /* string */
+		     	   mr->rdParam[3] ? (LPRECT16) &mr->rdParam[4]:NULL,  /* rectangle */
+		           sot,				/* string */
                            s1, dxx);                    /* length, dx array */
         if (dxx)                      
-          dprintf_metafile(stddeb,"EXTTEXTOUT len: %ld  (%hd %hd)  [%s].\n",
-            mr->rdSize,dxx[0],dxx[1],(char*) &(mr->rdParam[8]) );
+          dprintf_metafile(stddeb,"EXTTEXTOUT: %s  len: %ld  dx0: %d\n",
+            sot,mr->rdSize,dxx[0]);
        }
        break;
     
@@ -740,16 +748,29 @@
 	GlobalFree16(hndl);
 	break;
 
+     case META_DIBBITBLT:
+        {
+         LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParam[8]);
+         LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParam[0] );
+         StretchDIBits16(hdc,mr->rdParam[7],mr->rdParam[6],mr->rdParam[5],
+                       mr->rdParam[4],mr->rdParam[3],mr->rdParam[2],
+                       mr->rdParam[5],mr->rdParam[4],bits,info,
+                       DIB_RGB_COLORS,MAKELONG(mr->rdParam[0],mr->rdParam[1]));
+        }
+        break;	
+       
+     case META_SETTEXTJUSTIFICATION:
+       	SetTextJustification32(hdc, *(mr->rdParam + 1), *(mr->rdParam));
+	break;
+
 #define META_UNIMP(x) case x: fprintf(stderr,"PlayMetaFileRecord:record type "#x" not implemented.\n");break;
     META_UNIMP(META_SETTEXTCHAREXTRA)
-    META_UNIMP(META_SETTEXTJUSTIFICATION)
     META_UNIMP(META_FRAMEREGION)
     META_UNIMP(META_DRAWTEXT)
     META_UNIMP(META_SETDIBTODEV)
     META_UNIMP(META_ANIMATEPALETTE)
     META_UNIMP(META_SETPALENTRIES)
     META_UNIMP(META_RESIZEPALETTE)
-    META_UNIMP(META_DIBBITBLT)
     META_UNIMP(META_EXTFLOODFILL)
     META_UNIMP(META_RESETDC)
     META_UNIMP(META_STARTDOC)
diff --git a/resources/sysres_Es.rc b/resources/sysres_Es.rc
index e3b3dac..d7b048e 100644
--- a/resources/sysres_Es.rc
+++ b/resources/sysres_Es.rc
@@ -1,7 +1,7 @@
 
 SYSMENU MENU LOADONCALL MOVEABLE DISCARDABLE
 {
- MENUITEM "&Restaurer", 61728
+ MENUITEM "&Restaurar", 61728
  MENUITEM "&Mover", 61456
  MENUITEM "&Tamaño", 61440
  MENUITEM "Mi&nimizar", 61472
@@ -20,12 +20,12 @@
 	BEGIN
 		MENUITEM "&Undo", EM_UNDO32
 		MENUITEM SEPARATOR
-		MENUITEM "Cu&t", WM_CUT
-		MENUITEM "&Copy", WM_COPY
-		MENUITEM "&Paste", WM_PASTE
-		MENUITEM "&Delete", WM_CLEAR
+		MENUITEM "Co&rtar", WM_CUT
+		MENUITEM "&Copiar", WM_COPY
+		MENUITEM "&Pegar", WM_PASTE
+		MENUITEM "&Borrar", WM_CLEAR
 		MENUITEM SEPARATOR
-		MENUITEM "Select &All", EM_SETSEL32
+		MENUITEM "Seleccionar &todo", EM_SETSEL32
 	END
 }
 
@@ -148,36 +148,66 @@
 }
 
 
-CHOOSE_FONT DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 264, 134
+CHOOSE_FONT DIALOG DISCARDABLE  13, 54, 264, 147
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "Fuente"
 FONT 8, "Helv"
 {
- LTEXT "Fuente:", 1088, 6, 6, 40, 9
- LTEXT "", 1089, 60, 6, 150, 9
- DEFPUSHBUTTON "Aceptar", 1, 206, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
- PUSHBUTTON "Cancelar", 2, 206, 24, 56, 14, WS_GROUP | WS_TABSTOP
+    LTEXT           "&Fuente:",1088 ,6,3,40,9
+    COMBOBOX        1136 ,6,13,94,54,  CBS_OWNERDRAWFIXED | CBS_HASSTRINGS | CBS_DISABLENOSCROLL |
+                    CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP | CBS_SIMPLE
+    LTEXT           "Est&ilo de fuente:",1089 ,108,3,44,9
+    COMBOBOX        1137,108,13,64,54, CBS_OWNERDRAWFIXED | CBS_HASSTRINGS | CBS_DISABLENOSCROLL |
+                    WS_VSCROLL | WS_TABSTOP | CBS_SIMPLE
+    LTEXT           "&Tamaño:",1090,179,3,30,9
+    COMBOBOX        1138,179,13,32,54, CBS_OWNERDRAWFIXED | CBS_HASSTRINGS | CBS_DISABLENOSCROLL |
+                    WS_VSCROLL | WS_TABSTOP | CBS_SIMPLE | CBS_SORT
+    DEFPUSHBUTTON   "Aceptar",IDOK,218,6,40,14,WS_GROUP
+    PUSHBUTTON      "Cancelar",IDCANCEL,218,23,40,14,WS_GROUP
+    PUSHBUTTON      "A&plicar", 1026,218,40,40,14,WS_GROUP
+    PUSHBUTTON      "A&yuda" , 1038,218,57,40,14,WS_GROUP
+    GROUPBOX        "&Efectos",1072,6,72,84,34,WS_GROUP
+    CHECKBOX        "&Rayado", 1040, 10,82,50,10, BS_AUTOCHECKBOX | WS_TABSTOP
+    CHECKBOX        "&Subrayado", 1041, 10,94,50,10, BS_AUTOCHECKBOX
+    LTEXT           "&Color:", 1091 ,6,110,30,9
+    COMBOBOX        1139,6,120,84,100,CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_HASSTRINGS |
+                    CBS_AUTOHSCROLL |  WS_BORDER | WS_VSCROLL | WS_TABSTOP
+    GROUPBOX        "Ejemplo",1073,98,72,160,49,WS_GROUP
+    CTEXT           "AaBbYyZzÑñ",1093,104,81,149,37,SS_NOPREFIX | WS_VISIBLE
 }
 
 
-CHOOSE_COLOR DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 264, 200
+CHOOSE_COLOR DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 300, 200
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "Color"
 FONT 8, "Helv"
 {
- LTEXT "Colores &basicos:", 1088, 6, 6, 40, 9
- LTEXT "Colores person&alizados:", 1089, 6, 126, 40, 9
- LTEXT "Color|Sól&ido", 1090, 100, 146, 40, 9
- LTEXT "&Hue:", 1091, 150, 126, 40, 9
- LTEXT "&Sat:", 1092, 150, 146, 40, 9
- LTEXT "&Lum:", 1093, 150, 166, 40, 9
- LTEXT "&Rojo:", 1094, 150, 126, 40, 9
- LTEXT "&Verde:", 1095, 150, 146, 40, 9
- LTEXT "A&zul:", 1096, 150, 166, 40, 9
- DEFPUSHBUTTON "Aceptar", 1, 6, 182, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
- PUSHBUTTON "Agregar a los &colores personalizados", 1024, 120, 182, 100, 14, WS_GROUP | WS_TABSTOP
- PUSHBUTTON "Borrar colores personalizados", 1025, 6, 164, 56, 14, WS_GROUP | WS_TABSTOP
- PUSHBUTTON "Cancelar", 2, 76, 182, 56, 14, WS_GROUP | WS_TABSTOP
+ LTEXT "Colores &básicos:", 1088, 4, 4, 140, 10
+ LTEXT "Colores person&alizados:", 1089, 4, 106, 140, 10
+ LTEXT "Color|Só3l&ido", 1090, 150, 151, 48, 10
+ LTEXT   "&Rojo:", 726 /*1094*/,249,126,24,10
+ EDITTEXT 706, 275,124,18,12, WS_BORDER | WS_GROUP | WS_TABSTOP
+ LTEXT   "&Verde:",727/*1095*/,249,140,24,10
+ EDITTEXT 707, 275,138,18,12, WS_BORDER | WS_GROUP | WS_TABSTOP
+ LTEXT   "A&zul:",728 /*1096*/,249,154,24,10
+ EDITTEXT 708, 275,152,18,12, WS_BORDER | WS_GROUP | WS_TABSTOP
+ LTEXT  "&Tinte:" ,723 /*1091*/,202,126,22,10
+ EDITTEXT 703, 226,124,18,12, WS_BORDER | WS_GROUP | WS_TABSTOP
+ LTEXT  "&Sat.:" ,724 /*1092*/,202,140,22,10
+ EDITTEXT 704, 226,138,18,12, WS_BORDER | WS_GROUP | WS_TABSTOP
+ LTEXT  "&Lum.:" ,725 /*1093*/,202,154,22,10
+ EDITTEXT 705, 226,152,18,12, WS_BORDER | WS_GROUP | WS_TABSTOP
+ CONTROL "" ,720,"STATIC",SS_SIMPLE|WS_TABSTOP|WS_GROUP,4,14,140,86
+ CONTROL "" ,721,"STATIC",SS_SIMPLE|WS_TABSTOP|WS_GROUP,4,116,140,28
+ CONTROL "" ,710,"STATIC",WS_BORDER|SS_SIMPLE|WS_TABSTOP|WS_GROUP, 152,4,118,116 CONTROL "" ,702,"STATIC",SS_SIMPLE|WS_TABSTOP|WS_GROUP, 278,4,8,116
+ CONTROL "" ,702,"STATIC",SS_SIMPLE|WS_TABSTOP|WS_GROUP, 278,4,8,116
+ CONTROL "" ,709,"STATIC",SS_SIMPLE|WS_TABSTOP|WS_GROUP, 152,124,40,26
+ DEFPUSHBUTTON "Aceptar",  1,  4, 166, 44, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Cancelar", 2, 52, 166, 44, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "A&yuda", 1038,100,166, 44, 14
+ PUSHBUTTON "Agregar a los &colores personalizados", 712/*1024*/, 152, 166, 142, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "&Definir colores personalizados >>", 719/*1025*/,   4, 150, 142, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON  "&i",713,300,200,4,14   /* just a dummy:  'i' is  like  &i in "sol&id" */
 }
 
 
diff --git a/win32/cursoricon32.c b/win32/cursoricon32.c
index 0a22a38..4ce417e 100644
--- a/win32/cursoricon32.c
+++ b/win32/cursoricon32.c
@@ -339,7 +339,7 @@
         BITMAPINFOHEADER *bih = &pInfo->bmiHeader;
         RGBQUAD *rgb = pInfo->bmiColors;
         bits = (char *)bmi + size +
-            DIB_GetImageWidthBytes(bih->biWidth,bih->biBitCount)*bih->biHeight;
+            DIB_GetDIBWidthBytes(bih->biWidth,bih->biBitCount)*bih->biHeight;
         bih->biBitCount = 1;
         bih->biClrUsed = bih->biClrImportant = 2;
         rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
@@ -351,7 +351,7 @@
         BITMAPCOREHEADER *bch = (BITMAPCOREHEADER *)pInfo;
         RGBTRIPLE *rgb = (RGBTRIPLE *)(bch + 1);
         bits = (char *)bmi + size +
-            DIB_GetImageWidthBytes(bch->bcWidth,bch->bcBitCount)*bch->bcHeight;
+            DIB_GetDIBWidthBytes(bch->bcWidth,bch->bcBitCount)*bch->bcHeight;
         bch->bcBitCount = 1;
         rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
         rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
diff --git a/win32/file.c b/win32/file.c
index 98b4ffe..3bb4fed 100644
--- a/win32/file.c
+++ b/win32/file.c
@@ -25,6 +25,7 @@
 #define DEBUG_WIN32
 #include "debug.h"
 
+DWORD ErrnoToLastError(int errno_num);
 
 static int TranslateCreationFlags(DWORD create_flags);
 static int TranslateAccessFlags(DWORD access_flags);
diff --git a/win32/process.c b/win32/process.c
index 54baf23..deb34dd 100644
--- a/win32/process.c
+++ b/win32/process.c
@@ -325,7 +325,7 @@
 }
 
 /***********************************************************************
- *           WaitForSingleObject    (USER32.399)
+ *           WaitForMultipleObjects    (USER32.399)
  */
 DWORD MsgWaitForMultipleObjects(
 	DWORD nCount,HANDLE32 *pHandles,BOOL32 fWaitAll,DWORD dwMilliseconds,
diff --git a/windows/defwnd.c b/windows/defwnd.c
index 2083d51..1694a79 100644
--- a/windows/defwnd.c
+++ b/windows/defwnd.c
@@ -28,6 +28,8 @@
 static short iF10Key = 0;
 static short iMenuSysKey = 0;
 
+extern void  EndMenu(void);
+
 /***********************************************************************
  *           DEFWND_HandleWindowPosChanged
  *
@@ -328,8 +330,7 @@
 	break; 
 
     case WM_CANCELMODE:
-	/* EndMenu() should be called if in menu state but currently it's
-	   impossible to detect - menu code should be updated*/
+	if (wndPtr->parent == WIN_GetDesktop()) EndMenu();
 	if (GetCapture32() == wndPtr->hwndSelf) ReleaseCapture();
 	break;
 
diff --git a/windows/driver.c b/windows/driver.c
index 4eb0880..942ecc8 100644
--- a/windows/driver.c
+++ b/windows/driver.c
@@ -61,8 +61,8 @@
 	return 0;
     }
 
-    retval = CallDriverProc( lpdrv->lpDrvProc, 0L /* FIXME */, hDriver, msg,
-			     lParam1, lParam2 );
+    retval = CallDriverProc( (FARPROC16)lpdrv->lpDrvProc, 0L /* FIXME */, 
+                             hDriver, msg, lParam1, lParam2 );
 
     dprintf_driver( stddeb, "SendDriverMessage // retval = %ld\n", retval );
 
diff --git a/windows/graphics.c b/windows/graphics.c
index 3955937..44aa69f 100644
--- a/windows/graphics.c
+++ b/windows/graphics.c
@@ -11,6 +11,7 @@
 #include <X11/Xutil.h>
 #include <X11/Intrinsic.h>
 #include "graphics.h"
+#include "color.h"
 #include "bitmap.h"
 #include "gdi.h"
 #include "dc.h"
@@ -65,7 +66,7 @@
  */
 BOOL32 GRAPH_DrawBitmap( HDC32 hdc, HBITMAP32 hbitmap, 
 			 INT32 xdest, INT32 ydest, INT32 xsrc, INT32 ysrc, 
-                         INT32 width, INT32 height )
+                         INT32 width, INT32 height, BOOL32 bMono )
 {
     BITMAPOBJ *bmp;
     DC *dc;
@@ -73,24 +74,43 @@
     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return FALSE;
     if (!(bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC )))
         return FALSE;
+
+    xdest += dc->w.DCOrgX; ydest += dc->w.DCOrgY;
+
     XSetFunction( display, dc->u.x.gc, GXcopy );
     if (bmp->bitmap.bmBitsPixel == 1)
     {
         XSetForeground( display, dc->u.x.gc, dc->w.backgroundPixel );
         XSetBackground( display, dc->u.x.gc, dc->w.textPixel );
         XCopyPlane( display, bmp->pixmap, dc->u.x.drawable, dc->u.x.gc,
-                    xsrc, ysrc, width, height,
-                    dc->w.DCOrgX + xdest, dc->w.DCOrgY + ydest, 1 );
-        return TRUE;
+                    xsrc, ysrc, width, height, xdest, ydest, 1 );
     }
     else if (bmp->bitmap.bmBitsPixel == dc->w.bitsPerPixel)
     {
-        XCopyArea( display, bmp->pixmap, dc->u.x.drawable, dc->u.x.gc,
-                   xsrc, ysrc, width, height,
-                   dc->w.DCOrgX + xdest, dc->w.DCOrgY + ydest );
-        return TRUE;
+	if( bMono )
+	{
+	    INT32	plane;
+
+	    if( COLOR_GetMonoPlane(&plane) )
+	    {
+		XSetForeground( display, dc->u.x.gc, dc->w.backgroundPixel );
+		XSetBackground( display, dc->u.x.gc, dc->w.textPixel );
+	    }
+	    else
+	    {
+		XSetForeground( display, dc->u.x.gc, dc->w.textPixel );
+		XSetBackground( display, dc->u.x.gc, dc->w.backgroundPixel );
+	    }
+	    XCopyPlane( display, bmp->pixmap, dc->u.x.drawable, dc->u.x.gc,
+			xsrc, ysrc, width, height, xdest, ydest, plane );
+	}
+	else 
+	    XCopyArea( display, bmp->pixmap, dc->u.x.drawable, 
+		       dc->u.x.gc, xsrc, ysrc, width, height, xdest, ydest );
     }
     else return FALSE;
+
+    return TRUE;
 }
 
 
diff --git a/windows/keyboard.c b/windows/keyboard.c
index ce297aa..d1a6b11 100644
--- a/windows/keyboard.c
+++ b/windows/keyboard.c
@@ -639,7 +639,7 @@
       if (sendmsg)      /* found an accelerator, but send a message... ? */
       {
         INT16  iSysStat,iStat,mesg=0;
-        HMENU16 hSysMenu,hMenu;
+        HMENU16 hMenu;
         
         if (msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP)
           mesg=1;
@@ -651,16 +651,14 @@
             mesg=3;
           else
           {
-            hMenu=GetMenu32(hWnd);
-            hSysMenu=GetSystemMenu32(hWnd,FALSE);
-            if (hSysMenu)
-              iSysStat=GetMenuState32(hSysMenu,lpAccelTbl->tbl[i].wIDval,MF_BYCOMMAND);
-            else
-              iSysStat=-1;
-            if (hMenu)
-              iStat=GetMenuState32(hMenu,lpAccelTbl->tbl[i].wIDval,MF_BYCOMMAND);
-            else
-              iStat=-1;
+	    WND* wndPtr = WIN_FindWndPtr(hWnd);
+
+            hMenu = (wndPtr->dwStyle & WS_CHILD) ? 0 : (HMENU32)wndPtr->wIDmenu;
+	    iSysStat = (wndPtr->hSysMenu) ? GetMenuState32(GetSubMenu16(wndPtr->hSysMenu, 0),
+					    lpAccelTbl->tbl[i].wIDval, MF_BYCOMMAND) : -1 ;
+	    iStat = (hMenu) ? GetMenuState32(hMenu,
+					    lpAccelTbl->tbl[i].wIDval, MF_BYCOMMAND) : -1 ;
+
             if (iSysStat!=-1)
             {
               if (iSysStat & (MF_DISABLED|MF_GRAYED))
diff --git a/windows/mdi.c b/windows/mdi.c
index e08e08d..e301cbf 100644
--- a/windows/mdi.c
+++ b/windows/mdi.c
@@ -30,6 +30,8 @@
 #include "stddebug.h"
 #include "debug.h"
 
+#define MDIF_NEEDUPDATE		0x0001
+
 
 static HBITMAP16 hBmpClose   = 0;
 static HBITMAP16 hBmpRestore = 0;
@@ -57,9 +59,9 @@
 
 static void MDI_PostUpdate(HWND16 hwnd, MDICLIENTINFO* ci, WORD recalc)
 {
- if( !ci->sbNeedUpdate )
+ if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
    {
-      ci->sbNeedUpdate = TRUE;
+      ci->mdiFlags |= MDIF_NEEDUPDATE;
       PostMessage16( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
    }
  ci->sbRecalc = recalc;
@@ -980,7 +982,6 @@
 LRESULT MDIClientWndProc(HWND16 hwnd, UINT16 message, WPARAM16 wParam, LPARAM lParam)
 {
     LPCREATESTRUCT16     cs;
-    LPCLIENTCREATESTRUCT16 ccs;
     MDICLIENTINFO       *ci;
     RECT16		 rect;
     WND                 *w 	  = WIN_FindWndPtr(hwnd);
@@ -999,17 +1000,25 @@
 	 * so we have to keep track of what environment we're in. */
 
 	if( w->flags & WIN_ISWIN32 )
-	    ccs = (LPCLIENTCREATESTRUCT16) cs->lpCreateParams;
+	{
+#define ccs ((LPCLIENTCREATESTRUCT32)cs->lpCreateParams)
+	    ci->hWindowMenu	= ccs->hWindowMenu;
+	    ci->idFirstChild	= ccs->idFirstChild;
+#undef ccs
+	}
         else    
-	    ccs = (LPCLIENTCREATESTRUCT16) PTR_SEG_TO_LIN(cs->lpCreateParams);
+	{
+	    LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16) 
+				   PTR_SEG_TO_LIN(cs->lpCreateParams);
+	    ci->hWindowMenu	= ccs->hWindowMenu;
+	    ci->idFirstChild	= ccs->idFirstChild;
+	}
 
-	ci->hWindowMenu         = ccs->hWindowMenu;
-	ci->idFirstChild        = ccs->idFirstChild;
 	ci->hwndChildMaximized  = 0;
 	ci->nActiveChildren	= 0;
 	ci->nTotalCreated	= 0;
 	ci->frameTitle		= NULL;
-	ci->sbNeedUpdate	= 0;
+	ci->mdiFlags		= 0;
 	ci->self		= hwnd;
 	w->dwStyle             |= WS_CLIPCHILDREN;
 
@@ -1020,7 +1029,7 @@
         }
 	MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
 
-	AppendMenu32A( ccs->hWindowMenu, MF_SEPARATOR, 0, NULL );
+	AppendMenu32A( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
 
 	GetClientRect16(frameWnd->hwndSelf, &rect);
 	NC_HandleNCCalcSize( w, &rect );
@@ -1064,7 +1073,7 @@
 		((LONG) (ci->hwndChildMaximized>0) << 16));
 
       case WM_MDIICONARRANGE:
-	ci->sbNeedUpdate = TRUE;
+	ci->mdiFlags |= MDIF_NEEDUPDATE;
 	MDIIconArrange(hwnd);
 	ci->sbRecalc = SB_BOTH+1;
 	SendMessage16(hwnd,WM_MDICALCCHILDSCROLL,0,0L);
@@ -1090,17 +1099,17 @@
 #endif
 	
       case WM_MDITILE:
-	ci->sbNeedUpdate = TRUE;
+	ci->mdiFlags |= MDIF_NEEDUPDATE;
 	ShowScrollBar32(hwnd,SB_BOTH,FALSE);
 	MDITile(w, ci,wParam);
-        ci->sbNeedUpdate = FALSE;
+        ci->mdiFlags &= ~MDIF_NEEDUPDATE;
         return 0;
 
       case WM_VSCROLL:
       case WM_HSCROLL:
-	ci->sbNeedUpdate = TRUE;
+	ci->mdiFlags |= MDIF_NEEDUPDATE;
         ScrollChildren32(hwnd,message,wParam,lParam);
-	ci->sbNeedUpdate = FALSE;
+	ci->mdiFlags &= ~MDIF_NEEDUPDATE;
         return 0;
 
       case WM_SETFOCUS:
@@ -1132,27 +1141,27 @@
         return 0;
 
       case WM_SIZE:
-          if( ci->hwndChildMaximized )
-	  {
-	     WND*	child = WIN_FindWndPtr(ci->hwndChildMaximized);
-	     RECT16	rect  = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
+        if( ci->hwndChildMaximized )
+	{
+	    WND*	child = WIN_FindWndPtr(ci->hwndChildMaximized);
+	    RECT16	rect  = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
 
-	     AdjustWindowRectEx16(&rect, child->dwStyle, 0, child->dwExStyle);
-	     MoveWindow16(ci->hwndChildMaximized, rect.left, rect.top,
-			  rect.right - rect.left, rect.bottom - rect.top, 1);
-	  }
+	    AdjustWindowRectEx16(&rect, child->dwStyle, 0, child->dwExStyle);
+	    MoveWindow16(ci->hwndChildMaximized, rect.left, rect.top,
+			 rect.right - rect.left, rect.bottom - rect.top, 1);
+	}
 	else
 	  MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
 
 	break;
 
       case WM_MDICALCCHILDSCROLL:
-	if( ci->sbNeedUpdate )
-	  if( ci->sbRecalc )
-	    {
-	      CalcChildScroll(hwnd, ci->sbRecalc-1);
-	      ci->sbRecalc = ci->sbNeedUpdate = 0;
-	    }
+	if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
+	{
+	    CalcChildScroll(hwnd, ci->sbRecalc-1);
+	    ci->sbRecalc = 0;
+	    ci->mdiFlags &= ~MDIF_NEEDUPDATE;
+	}
 	return 0;
     }
     
@@ -1236,20 +1245,20 @@
 
 	    if( !(wndPtr->parent->dwStyle & WS_MINIMIZE) 
 		&& ci->hwndActiveChild && !ci->hwndChildMaximized )
-	      {
+	    {
 		/* control menu is between the frame system menu and 
 		 * the first entry of menu bar */
 
-		if( wParam == VK_LEFT ) 
-		  { if( wndPtr->parent->wIDmenu != LOWORD(lParam) ) break; }
-		else if( wParam == VK_RIGHT )
-		  { if( GetSystemMenu16( wndPtr->parent->hwndSelf, 0) 
-                          != LOWORD(lParam) ) break; }
-		else break;
-		
-		return MAKELONG( GetSystemMenu16(ci->hwndActiveChild, 0), 
-				 ci->hwndActiveChild );
-	      }
+		if( (wParam == VK_LEFT &&
+		     wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
+		    (wParam == VK_RIGHT &&
+		     GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
+		{
+		    wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
+		    return MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0), 
+						  ci->hwndActiveChild);
+		}
+	    }
 	    break;
 	}
     }
@@ -1405,8 +1414,7 @@
 	return 0;
 
       case WM_SETVISIBLE:
-         if( ci->hwndChildMaximized)
-             ci->sbNeedUpdate = 0;
+         if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
 	 else
             MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
 	break;
@@ -1469,7 +1477,7 @@
       case WM_NEXTMENU:
 
 	if( wParam == VK_LEFT )		/* switch to frame system menu */
-	  return MAKELONG( GetSystemMenu16(clientWnd->parent->hwndSelf, 0), 
+	  return MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0), 
 			   clientWnd->parent->hwndSelf );
 	if( wParam == VK_RIGHT )	/* to frame menu bar */
 	  return MAKELONG( clientWnd->parent->wIDmenu,
@@ -1598,42 +1606,49 @@
  */
 BOOL16 TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
 {
-  WND* clientWnd = WIN_FindWndPtr( hwndClient);
-  WND* wnd;
-  MDICLIENTINFO       *ci     = NULL;
-  WPARAM16	       wParam = 0;
+    WND* clientWnd = WIN_FindWndPtr( hwndClient);
+    WND* wnd;
+    MDICLIENTINFO     *ci     = NULL;
+    WPARAM16	       wParam = 0;
 
-  if( (msg->message != WM_KEYDOWN && msg->message != WM_SYSKEYDOWN) || !clientWnd )
-    return 0;
+    if( clientWnd && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
+    {
+	MDICLIENTINFO	*ci = NULL;
+	WND*		wnd;
 
-  ci = (MDICLIENTINFO*) clientWnd->wExtra;
-  wnd = WIN_FindWndPtr(ci->hwndActiveChild);
- 
-  if( !wnd ) return 0;
+	ci = (MDICLIENTINFO*) clientWnd->wExtra;
+	wnd = WIN_FindWndPtr(ci->hwndActiveChild);
+	if( wnd && !(wnd->dwStyle & WS_DISABLED) )
+	{
+	    WPARAM16	wParam = 0;
+
+	    /* translate if the Ctrl key is down and Alt not. */
   
-  if( wnd->dwStyle & WS_DISABLED ) return 0;
-   
-  if ((GetKeyState32(VK_CONTROL) & 0x8000) && !(GetKeyState32(VK_MENU) & 0x8000))
-    switch( msg->wParam )
-      {
-	case VK_F6:
-	case VK_SEPARATOR:
-	     wParam = ( GetKeyState32(VK_SHIFT) & 0x8000 )? SC_NEXTWINDOW: SC_PREVWINDOW;
-	     break;
-        case VK_F4:
-	case VK_RBUTTON:
-	     wParam = SC_CLOSE; 
-	     break;
-	default:
-	     return 0;
-      }
-  else
-      return 0;
-
-  dprintf_mdi(stddeb,"TranslateMDISysAccel: wParam = %04x\n", wParam);
-
-  SendMessage16(ci->hwndActiveChild,WM_SYSCOMMAND, wParam, (LPARAM)msg->wParam);
-  return 1;
+	    if( (GetKeyState32(VK_CONTROL) & 0x8000) && 
+	       !(GetKeyState32(VK_MENU) & 0x8000))
+	    {
+		switch( msg->wParam )
+		{
+		    case VK_F6:
+		    case VK_SEPARATOR:
+			 wParam = ( GetKeyState32(VK_SHIFT) & 0x8000 )
+				  ? SC_NEXTWINDOW : SC_PREVWINDOW;
+			 break;
+		    case VK_F4:
+		    case VK_RBUTTON:
+			 wParam = SC_CLOSE; 
+			 break;
+		    default:
+			 return 0;
+		}
+	        dprintf_mdi(stddeb,"TranslateMDISysAccel: wParam = %04x\n", wParam);
+	        SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND, 
+					wParam, (LPARAM)msg->wParam);
+	        return 1;
+	    }
+	}
+    }
+    return 0; /* failure */
 }
 
 
diff --git a/windows/message.c b/windows/message.c
index 751212c..80c3e5c 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -1055,7 +1055,7 @@
         fprintf( stderr, "SendMessage16: invalid hwnd %04x\n", hwnd );
         return 0;
     }
-    if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
+    if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
         return 0;  /* Don't send anything if the task is dying */
     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
         return MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam );
@@ -1120,7 +1120,7 @@
         return 0;
     }
 
-    if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
+    if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
         return 0;  /* Don't send anything if the task is dying */
 
     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
@@ -1168,7 +1168,7 @@
         fprintf( stderr, "SendMessage32W: invalid hwnd %08x\n", hwnd );
         return 0;
     }
-    if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
+    if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
         return 0;  /* Don't send anything if the task is dying */
     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
     {
diff --git a/windows/nonclient.c b/windows/nonclient.c
index e0c6412..08ff98b 100644
--- a/windows/nonclient.c
+++ b/windows/nonclient.c
@@ -465,11 +465,11 @@
     if( !(wndPtr->flags & WIN_MANAGED) )
     {
       NC_GetInsideRect( hwnd, &rect );
-      GRAPH_DrawBitmap( hdc, (IsZoomed32(hwnd) ?
-			     (down ? hbitmapRestoreD : hbitmapRestore) :
-			     (down ? hbitmapMaximizeD : hbitmapMaximize)),
+      GRAPH_DrawBitmap( hdc, (IsZoomed32(hwnd) 
+			     ? (down ? hbitmapRestoreD : hbitmapRestore)
+			     : (down ? hbitmapMaximizeD : hbitmapMaximize)),
 		        rect.right - SYSMETRICS_CXSIZE - 1, rect.top,
-		        0, 0, SYSMETRICS_CXSIZE+1, SYSMETRICS_CYSIZE );
+		        0, 0, SYSMETRICS_CXSIZE+1, SYSMETRICS_CYSIZE, FALSE );
     }
 }
 
@@ -488,7 +488,7 @@
       if (wndPtr->dwStyle & WS_MAXIMIZEBOX) rect.right -= SYSMETRICS_CXSIZE+1;
       GRAPH_DrawBitmap( hdc, (down ? hbitmapMinimizeD : hbitmapMinimize),
 		        rect.right - SYSMETRICS_CXSIZE - 1, rect.top,
-		        0, 0, SYSMETRICS_CXSIZE+1, SYSMETRICS_CYSIZE );
+		        0, 0, SYSMETRICS_CXSIZE+1, SYSMETRICS_CYSIZE, FALSE );
     }
 }
 
@@ -927,19 +927,18 @@
  * Initialisation of a move or resize, when initiatied from a menu choice.
  * Return hit test code for caption or sizing border.
  */
-static LONG NC_StartSizeMove( HWND32 hwnd, WPARAM16 wParam,
+static LONG NC_StartSizeMove( WND* wndPtr, WPARAM16 wParam,
                               POINT16 *capturePoint )
 {
     LONG hittest = 0;
     POINT16 pt;
     MSG16 msg;
-    WND * wndPtr = WIN_FindWndPtr( hwnd );
 
     if ((wParam & 0xfff0) == SC_MOVE)
     {
 	  /* Move pointer at the center of the caption */
 	RECT32 rect;
-	NC_GetInsideRect( hwnd, &rect );
+	NC_GetInsideRect( wndPtr->hwndSelf, &rect );
 	if (wndPtr->dwStyle & WS_SYSMENU)
 	    rect.left += SYSMETRICS_CXSIZE + 1;
 	if (wndPtr->dwStyle & WS_MINIMIZEBOX)
@@ -948,20 +947,21 @@
 	    rect.right -= SYSMETRICS_CXSIZE + 1;
 	pt.x = wndPtr->rectWindow.left + (rect.right - rect.left) / 2;
 	pt.y = wndPtr->rectWindow.top + rect.top + SYSMETRICS_CYSIZE/2;
+	hittest = HTCAPTION;
+	*capturePoint = pt;
+
 	if (wndPtr->dwStyle & WS_CHILD)
 	    ClientToScreen16( wndPtr->parent->hwndSelf, &pt );
-	hittest = HTCAPTION;
     }
     else  /* SC_SIZE */
     {
-	SetCapture32(hwnd);
 	while(!hittest)
 	{
             MSG_InternalGetMessage( &msg, 0, 0, MSGF_SIZE, PM_REMOVE, FALSE );
 	    switch(msg.message)
 	    {
 	    case WM_MOUSEMOVE:
-		hittest = NC_HandleNCHitTest( hwnd, msg.pt );
+		hittest = NC_HandleNCHitTest( wndPtr->hwndSelf, msg.pt );
 		pt = msg.pt;
 		if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT))
 		    hittest = 0;
@@ -998,10 +998,11 @@
 		}
 	    }
 	}
+	*capturePoint = pt;
     }
-    *capturePoint = pt;
-    SetCursorPos32( capturePoint->x, capturePoint->y );
-    NC_HandleSetCursor( hwnd, (WPARAM16)hwnd, MAKELONG( hittest, WM_MOUSEMOVE ));
+    SetCursorPos32( pt.x, pt.y );
+    NC_HandleSetCursor( wndPtr->hwndSelf, 
+			wndPtr->hwndSelf, MAKELONG( hittest, WM_MOUSEMOVE ));
     return hittest;
 }
 
@@ -1030,17 +1031,18 @@
     if ((wParam & 0xfff0) == SC_MOVE)
     {
 	if (!(wndPtr->dwStyle & WS_CAPTION)) return;
-	if (!hittest) hittest = NC_StartSizeMove( hwnd, wParam, &capturePoint );
+	if (!hittest) 
+	     hittest = NC_StartSizeMove( wndPtr, wParam, &capturePoint );
 	if (!hittest) return;
     }
     else  /* SC_SIZE */
     {
 	if (!thickframe) return;
-	if (hittest) hittest += HTLEFT-1;
+	if ( hittest && hittest != HTSYSMENU ) hittest += 2;
 	else
 	{
 	    SetCapture32(hwnd);
-	    hittest = NC_StartSizeMove( hwnd, wParam, &capturePoint );
+	    hittest = NC_StartSizeMove( wndPtr, wParam, &capturePoint );
 	    if (!hittest)
 	    {
 		ReleaseCapture();
@@ -1055,7 +1057,8 @@
     sizingRect = wndPtr->rectWindow;
     if (wndPtr->dwStyle & WS_CHILD)
 	GetClientRect16( wndPtr->parent->hwndSelf, &mouseRect );
-    else SetRect16(&mouseRect, 0, 0, SYSMETRICS_CXSCREEN, SYSMETRICS_CYSCREEN);
+    else 
+        SetRect16(&mouseRect, 0, 0, SYSMETRICS_CXSCREEN, SYSMETRICS_CYSCREEN);
     if (ON_LEFT_BORDER(hittest))
     {
 	mouseRect.left  = MAX( mouseRect.left, sizingRect.right-maxTrack.x );
@@ -1361,7 +1364,8 @@
     case HTBOTTOM:
     case HTBOTTOMLEFT:
     case HTBOTTOMRIGHT:
-	SendMessage16( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - HTLEFT+1, lParam);
+	/* make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU */
+	SendMessage16( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - 2, lParam);
 	break;
 
     case HTBORDER:
@@ -1416,14 +1420,15 @@
 {
     WND *wndPtr = WIN_FindWndPtr( hwnd );
     POINT32 pt32;
+    UINT16 uCommand = wParam & 0xFFF0;
 
     dprintf_nonclient(stddeb, "Handling WM_SYSCOMMAND %x %d,%d\n", 
 		      wParam, pt.x, pt.y );
 
-    if (wndPtr->dwStyle & WS_CHILD && wParam != SC_KEYMENU )
+    if (wndPtr->dwStyle & WS_CHILD && uCommand != SC_KEYMENU )
         ScreenToClient16( wndPtr->parent->hwndSelf, &pt );
 
-    switch (wParam & 0xfff0)
+    switch (uCommand)
     {
     case SC_SIZE:
     case SC_MOVE:
diff --git a/windows/queue.c b/windows/queue.c
index a74945c..9845c1a 100644
--- a/windows/queue.c
+++ b/windows/queue.c
@@ -19,7 +19,7 @@
 #define MAX_QUEUE_SIZE   120  /* Max. size of a message queue */
 
 static HQUEUE16 hFirstQueue = 0;
-static HQUEUE16 hDoomedQueue = 0;
+static HQUEUE16 hExitingQueue = 0;
 static HQUEUE16 hmemSysMsgQueue = 0;
 static MESSAGEQUEUE *sysMsgQueue = NULL;
 
@@ -94,20 +94,20 @@
 
 
 /***********************************************************************
- *	     QUEUE_IsDoomedQueue
+ *	     QUEUE_IsExitingQueue
  */
-BOOL32 QUEUE_IsDoomedQueue( HQUEUE16 hQueue )
+BOOL32 QUEUE_IsExitingQueue( HQUEUE16 hQueue )
 {
-    return (hDoomedQueue && (hQueue == hDoomedQueue));
+    return (hExitingQueue && (hQueue == hExitingQueue));
 }
 
 
 /***********************************************************************
- *	     QUEUE_SetDoomedQueue
+ *	     QUEUE_SetExitingQueue
  */
-void QUEUE_SetDoomedQueue( HQUEUE16 hQueue )
+void QUEUE_SetExitingQueue( HQUEUE16 hQueue )
 {
-    hDoomedQueue = hQueue;
+    hExitingQueue = hQueue;
 }
 
 
diff --git a/windows/user.c b/windows/user.c
index b20670f..231761a 100644
--- a/windows/user.c
+++ b/windows/user.c
@@ -21,7 +21,7 @@
 
 WORD USER_HeapSel = 0;
 
-extern BOOL32 MENU_SwitchTPWndTo(HTASK16);
+extern BOOL32 MENU_PatchResidentPopup( HQUEUE16, WND* );
 extern void QUEUE_FlushMessages(HQUEUE16);
 
 /***********************************************************************
@@ -108,7 +108,7 @@
 }
 
 /**********************************************************************
- *					USER_AppExit
+ *           USER_AppExit
  */
 void USER_AppExit( HTASK16 hTask, HINSTANCE16 hInstance, HQUEUE16 hQueue )
 {
@@ -123,16 +123,16 @@
 	desktop->hmemTaskQ = GetTaskQueue(TASK_GetNextTask(hTask));
 
     /* Patch resident popup menu window */
-    MENU_SwitchTPWndTo(0);
+    MENU_PatchResidentPopup( hQueue, NULL );
 
     TIMER_RemoveQueueTimers( hQueue );
 
     QUEUE_FlushMessages( hQueue );
     HOOK_FreeQueueHooks( hQueue );
 
-    QUEUE_SetDoomedQueue( hQueue );
+    QUEUE_SetExitingQueue( hQueue );
     WIN_ResetQueueWindows( desktop->child, hQueue, (HQUEUE16)0);
-    QUEUE_SetDoomedQueue( 0 );
+    QUEUE_SetExitingQueue( 0 );
 
     /* Free the message queue */
 
diff --git a/windows/win.c b/windows/win.c
index e5be6f4..f093af1 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -43,6 +43,7 @@
 static WORD wDragWidth = 4;
 static WORD wDragHeight= 3;
 
+extern BOOL32 MENU_PatchResidentPopup( HQUEUE16, WND* );
 extern HCURSOR16 CURSORICON_IconToCursor(HICON16, BOOL32);
 extern HWND32 CARET_GetHwnd(void);
 extern BOOL32 WINPOS_ActivateOtherWindow(WND* pWnd);
@@ -569,8 +570,9 @@
     wndPtr->pVScroll       = NULL;
     wndPtr->pHScroll       = NULL;
     wndPtr->pProp          = NULL;
-    wndPtr->hSysMenu       = MENU_GetDefSysMenu();
     wndPtr->userdata       = 0;
+    wndPtr->hSysMenu       = (wndPtr->dwStyle & WS_SYSMENU)
+			     ? MENU_GetSysMenu( hwnd, 0 ) : 0;
 
     if (classPtr->cbWndExtra) memset( wndPtr->wExtra, 0, classPtr->cbWndExtra);
 
@@ -1000,7 +1002,7 @@
         /* FIXME: clean up palette - see "Internals" p.352 */
     }
 
-    if( !QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ) )
+    if( !QUEUE_IsExitingQueue(wndPtr->hmemTaskQ) )
 	 WIN_SendParentNotify( hwnd, WM_DESTROY, wndPtr->wIDmenu, (LPARAM)hwnd );
     if (!IsWindow32(hwnd)) return TRUE;
 
@@ -1012,7 +1014,7 @@
     {
         SetWindowPos32( hwnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW |
 		        SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|
-		        ((QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))?SWP_DEFERERASE:0) );
+		        ((QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))?SWP_DEFERERASE:0) );
 	if (!IsWindow32(hwnd)) return TRUE;
     }
 
@@ -1020,6 +1022,9 @@
 
     if( !(wndPtr->dwStyle & WS_CHILD) )
     {
+      /* make sure top menu popup doesn't get destroyed */
+      MENU_PatchResidentPopup( TRUE, wndPtr );
+
       for (;;)
       {
         WND *siblingPtr = wndPtr->parent->child;  /* First sibling */
diff --git a/windows/winpos.c b/windows/winpos.c
index d588de4..9b90564 100644
--- a/windows/winpos.c
+++ b/windows/winpos.c
@@ -1181,7 +1181,7 @@
       hwndPrevActive = 0;
 
   if( hwndActive != pWnd->hwndSelf && 
-    ( hwndActive || QUEUE_IsDoomedQueue(pWnd->hmemTaskQ)) )
+    ( hwndActive || QUEUE_IsExitingQueue(pWnd->hmemTaskQ)) )
       return 0;
 
   if( pWnd->dwStyle & WS_POPUP &&