- got rid of all the internal MM tweaks to load builtin MCI
  drivers. They are all seen as drivers, loaded as DLLs and standard
  module loadorder is used to know which type to use (builtin vs
  native).
- first full working implementation of mmThread??? functions (to
  support gracefully native MCI drivers).
- support of mmShowMMCPLPropertySheet.
- fix of some heap validate bugs (thanks to Ulrich for reporting them).

diff --git a/documentation/status/multimedia b/documentation/status/multimedia
index f00f556..a30741c 100644
--- a/documentation/status/multimedia
+++ b/documentation/status/multimedia
@@ -15,6 +15,7 @@
 1. Lowlevel layers
 
    Following lowlevel layers are implemented:
+
 1.1 (Waveform) Audio
 
    The API consists of the waveIn*/waveOut* functions found in
@@ -29,18 +30,18 @@
 
    The implementation contains all features commonly used, but has several
    problems. For instance:
-      Writes and reads are not done asynchronously as they are supposed to
-   be done. This breaks some programs (soundrec.exe from the Windows applets),
-   but doesn't worry other programs. Some callbacks are probably done
-   incorrectly (there are reports of some broken multimedia applications,
-   but I haven't found one yet.)
+      Writes are not done asynchronously as they are supposed to be done.
+   This breaks some programs (soundrec.exe from the Windows applets),
+   but doesn't worry other programs. 
 
    TODO:
-   	- add asynchronous writes and reads (must use threads)
-	- check the callback functions
+   	- add asynchronous writes (must use threads)
 	- verify all functions for correctness
 	- add drivers for other soundsystems (Sun Audio, remote audio systems
 	  (using X extensions, ...), ALSA
+	- WaveHdr must be sent though mmsystem.c to get the linear address
+	  set correctly. An application calling directly (wod|wid)Message
+	  will fail
 
 1.2 Mixer
 
@@ -77,9 +78,10 @@
           use existing instrument definition (from playmidi or kmid)
           with a .winerc option
         - have a look at OPL/3 ?
-	- a hack is used in mmsystem.c (setting reserved to the 32 bit linear
-	  address of the block whatever the call is made from 16 or 32 bits 
-	  code...). this should be made in midi.c I think
+	- MidiHdr must be sent though mmsystem.c to get the linear address
+	  set correctly. An application calling directly (wod|wid)Message
+	  will fail
+	- implement asynchronous playback of MidiHdr 
 
 1.4 Timers
 
@@ -92,7 +94,7 @@
    and 'Pinball! SpaceCadet' at least start up.
 
    TODO:
-   	- Implemented asynchronous timers (using a thread probably)
+   	- Implemented asynchronous timers (using the service thread)
 
 1.5 MMIO
    
@@ -138,20 +140,19 @@
    allocation and calls.
 
    The implementation is not complete.
+ 
+   MCI drivers are seen as regular WINE modules, and can be loaded 
+   (with a correct loadorder between builtin, native, elfdll, so), as
+   any other DLL. Please note, that MCI drivers module names must
+   bear the .drv extension to be correctly understood.
 
-   There is a first shot at using native (MS provided) MCI
-   drivers. For this to work, there are two .winerc options to be
-   used:
-	- key 'mci' in [option] section
+   The list of available MCI drivers is obtained as follows:
+	1/ key 'mci' in [option] section from .winerc (or wineconf)
 		mci=CDAUDIO:SEQUENCER
 	  gives the list of MCI drivers (names, in uppercase only) to
-	  be used in WINE. This list, when defined, supercedes the mci
+	  be used in WINE.
+	2/ This list, when defined, supercedes the mci
 	  key in c:\windows\system.ini
-        - key 'mciExternal' in [option] section
-		mciExternal=CDAUDIO
-	  gives the list of MCI drivers to be loaded from Windows
-	  installation. Since, drivers are DLLs, drivers are searched
-	  (and loaded) as DLLs are.
 
    TODO:
 	- support windows MCI drivers (should be possible for they usually 
@@ -164,6 +165,7 @@
 	- implement other stuff as yet unknown
 	- in mciString(), make use of hiword from mciSendMessage
           return value to convert value into string...
+	- move mci drivers as regular DLLs (loading in wine, elfglue...)
 
    WINE implements several MCI midlevel drivers:
 
@@ -193,7 +195,12 @@
    It uses the lowlevel audio API (although not abstracted correctly).
    FIXME: The MCI_STATUS command is broken.
 
-   TODO: - check for correctness
+   TODO: 
+	- check for correctness
+	- better use of asynchronous playback from low level
+   
+   Native MCIWAVE has been working but is currently blocked by
+   scheduling issues.
 
 2.3 MIDI/SEQUENCER
    
@@ -205,6 +212,9 @@
    	- implement it correctly
 	- finish asynchronous commands
 
+   Native MCIMIDI has been working but is currently blocked by
+   scheduling issues.
+
 2.4 MCIANIM
 
    The implementation consists of stubs and is in multimedia/mcianim.c.
@@ -213,6 +223,14 @@
    	- implement it, probably using xanim or something similair. Could
 	  also be implemented by using the Windows MCI video drivers.
 
+2.5 MCIAVI
+
+   The implementation consists of stubs and is in multimedia/mciavi.c.
+
+   TODO: 
+   	- implement it, probably using xanim or something similair. Could
+	  also be implemented by using the Windows MCI video drivers.
+
 3 High-level layers
 
-   The rest (basically the MMSYSTEM and WINMM DLLs entry points.
+   The rest (basically the MMSYSTEM and WINMM DLLs entry points).
diff --git a/if1632/mmsystem.spec b/if1632/mmsystem.spec
index 524994c..51430fc 100644
--- a/if1632/mmsystem.spec
+++ b/if1632/mmsystem.spec
@@ -1,5 +1,6 @@
 name	mmsystem
 type	win16
+init	MMSYSTEM_LibMain
 
 #1      pascal  MMSYSTEM_WEP(word word word ptr) MMSYSTEM_WEP
 2      pascal  SNDPLAYSOUND(ptr word) sndPlaySoundA
@@ -147,7 +148,7 @@
 1123   pascal  mmThreadIsCurrent(word) mmThreadIsCurrent16
 1124   pascal  mmThreadIsValid(word) mmThreadIsValid16
 1125   pascal  mmThreadGetTask(word) mmThreadGetTask16
-1150   pascal  mmShowMMCPLPropertySheet(word word word word word word word) mmShowMMCPLPropertySheet16
+1150   pascal  mmShowMMCPLPropertySheet(word str str str) mmShowMMCPLPropertySheet16
 
 1210   pascal  mmioOpen(str ptr long) mmioOpen16
 1211   pascal  mmioClose(word word) mmioClose16
@@ -175,4 +176,4 @@
 #2006   stub    WINMMSL_THUNKDATA16
 
 # this is a wine only exported function. Is there another way to do it ?
-2047   pascal  WINE_mmThreadingEntryPoint(long) WINE_mmThreadingEntryPoint 
\ No newline at end of file
+2047   pascal  WINE_mmThreadEntryPoint(long) WINE_mmThreadEntryPoint
diff --git a/include/multimedia.h b/include/multimedia.h
index 4c3f4a2..16d1166 100644
--- a/include/multimedia.h
+++ b/include/multimedia.h
@@ -2,9 +2,10 @@
 
 /*****************************************************************************
  * Copyright 1998, Luiz Otavio L. Zorzella
+ *           1999, Eric Pouech
  *
  * File:      multimedia.h
- * Purpose:   multimedia declarations
+ * Purpose:   multimedia declarations (internal to multimedia DLLs)
  *
  *****************************************************************************
  */
@@ -44,7 +45,7 @@
 #endif
 
 typedef struct {
-	HDRVR16			hDrv;
+	HDRVR			hDrv;
 	DRIVERPROC16		driverProc;
 	MCI_OPEN_DRIVER_PARMS16	modp;
 	MCI_OPEN_PARMS16	mop;
@@ -62,41 +63,50 @@
 
 typedef struct {
        DWORD			dwSignature;		/* 00 "BSIL" when ok, 0xDEADDEAD when being deleted */
-       DWORD			dwCounter;		/* 04 */
+       DWORD			dwCounter;		/* 04 > 1 when in mmThread functions */
        HANDLE			hThread;		/* 08 hThread */
-       DWORD                    dwThreadId;     	/* 0C */
-       FARPROC16		fpThread;		/* 10 segmented address of thread proc */
-       DWORD			dwThreadPmt;    	/* 14 parameter to be called upon thread creation */
-       DWORD                    dwUnknown3;     	/* 18 increment interlocked ? */
-       DWORD                    hEvent;     		/* 1C event */
-       DWORD                    dwUnknown5;     	/* 20 */
-       DWORD                    dwStatus;       	/* 24 0, 10, 20, 30 */
+       DWORD                    dwThreadID;     	/* 0C */
+       FARPROC16		fpThread;		/* 10 address of thread proc (segptr or lin depending on dwFlags) */
+       DWORD			dwThreadPmt;    	/* 14 parameter to be passed upon thread creation to fpThread */
+       DWORD                    dwSignalCount;	     	/* 18 counter used for signaling */
+       HANDLE                   hEvent;     		/* 1C event */
+       HANDLE                   hVxD;		     	/* 20 return from OpenVxDHandle */
+       DWORD                    dwStatus;       	/* 24 0x00, 0x10, 0x20, 0x30 */
        DWORD			dwFlags;		/* 28 dwFlags upon creation */
        HANDLE16			hTask;          	/* 2C handle to created task */
 } WINE_MMTHREAD;
 
-#define MCI_GetDrv(wDevID) 	(&mciDrv[MCI_DevIDToIndex(wDevID)])
-#define MCI_GetOpenDrv(wDevID)	(&(MCI_GetDrv(wDevID)->mop))
+typedef enum {
+    MCI_MAP_NOMEM, 	/* ko, memory problem */
+    MCI_MAP_MSGERROR, 	/* ko, unknown message */
+    MCI_MAP_OK, 	/* ok, no memory allocated. to be sent to 16 bit proc. */
+    MCI_MAP_OKMEM, 	/* ok, some memory allocated, need to call MCI_UnMapMsg32ATo16. to be sent to 16 bit proc. */
+    MCI_MAP_PASS	/* ok, no memory allocated. to be sent to 32 bit proc */
+} MCI_MapType;
 
 /* function prototypes */
-extern BOOL MULTIMEDIA_Init(void);
+
+#define MCI_GetDrv(wDevID) 	(&mciDrv[MCI_DevIDToIndex(wDevID)])
+#define MCI_GetOpenDrv(wDevID)	(&(MCI_GetDrv(wDevID)->mop))
 
 extern int    			MCI_DevIDToIndex(UINT16 wDevID);
 extern UINT16 			MCI_FirstDevID(void);
 extern UINT16 			MCI_NextDevID(UINT16 wDevID);
 extern BOOL 			MCI_DevIDValid(UINT16 wDevID);
 
-extern int			MCI_MapMsg16To32A(WORD uDevType, WORD wMsg, DWORD* lParam);
-extern int			MCI_UnMapMsg16To32A(WORD uDevTyp, WORD wMsg, DWORD lParam);
+extern MCI_MapType		MCI_MapMsg16To32A(WORD uDevType, WORD wMsg, DWORD* lParam);
+extern MCI_MapType		MCI_UnMapMsg16To32A(WORD uDevTyp, WORD wMsg, DWORD lParam);
 
 extern DWORD 			MCI_Open(DWORD dwParam, LPMCI_OPEN_PARMSA lpParms);
 extern DWORD 			MCI_Close(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms);
 extern DWORD 			MCI_SysInfo(UINT uDevID, DWORD dwFlags, LPMCI_SYSINFO_PARMSA lpParms);
 
-typedef LONG			(*MCIPROC16)(DWORD, HDRVR16,  WORD, DWORD, DWORD);
-typedef LONG			(*MCIPROC)(DWORD, HDRVR16, DWORD, DWORD, DWORD);
+typedef LONG			(*MCIPROC16)(DWORD, HDRVR16, WORD, DWORD, DWORD);
+typedef LONG			(*MCIPROC)(DWORD, HDRVR, DWORD, DWORD, DWORD);
 
-extern WORD		   	MCI_GetDevType(LPCSTR str);
+extern WORD		   	MCI_GetDevTypeFromString(LPCSTR str);
+extern LPCSTR		   	MCI_GetStringFromDevType(WORD type);
+
 extern DWORD			MCI_WriteString(LPSTR lpDstStr, DWORD dstSize, LPCSTR lpSrcStr);
 extern const char* 		MCI_CommandToString(UINT16 wMsg);
 
@@ -106,28 +116,34 @@
 
 extern UINT16		WINAPI	MCI_DefYieldProc(UINT16 wDevID, DWORD data);
 
-typedef struct {
-    WORD	uDevType;
-    char*	lpstrName;
-    MCIPROC	lpfnProc;
-} MCI_WineDesc;
-
-extern	MCI_WineDesc		MCI_InternalDescriptors[];
-
 extern LRESULT			MCI_CleanUp(LRESULT dwRet, UINT wMsg, DWORD dwParam2, BOOL bIs32);
 
-extern DWORD 			MCI_SendCommand(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2);
+extern DWORD 			MCI_SendCommandFrom32(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2);
+extern DWORD 			MCI_SendCommandFrom16(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2);
 extern DWORD 			MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2, UINT size);
 
-LONG 				MCIWAVE_DriverProc(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
+LONG 				MCIWAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
 						   DWORD dwParam1, DWORD dwParam2);
-LONG 				MCIMIDI_DriverProc(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
+LONG 				MCIMIDI_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
 						   DWORD dwParam1, DWORD dwParam2);
-LONG				MCICDAUDIO_DriverProc(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
+LONG				MCICDAUDIO_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
 						      DWORD dwParam1, DWORD dwParam2);
-LONG				MCIANIM_DriverProc(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
+LONG				MCIANIM_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
 						   DWORD dwParam1, DWORD dwParam2);
-LONG				MCIAVI_DriverProc(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
+LONG				MCIAVI_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
 						  DWORD dwParam1, DWORD dwParam2);
 
+HINSTANCE16	WINAPI 		mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt);
+void    	WINAPI  	mmTaskBlock16(HINSTANCE16 hInst);
+LRESULT 	WINAPI 		mmTaskSignal16(HTASK16 ht);
+void    	WINAPI  	mmTaskYield16(void);
+
+void    	WINAPI  	WINE_mmThreadEntryPoint(DWORD _pmt);
+LRESULT 	WINAPI 		mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE lpHndl, DWORD dwPmt, DWORD dwFlags);
+void 		WINAPI 		mmThreadSignal16(HANDLE16 hndl);
+void    	WINAPI 		mmThreadBlock16(HANDLE16 hndl);
+HANDLE16 	WINAPI 		mmThreadGetTask16(HANDLE16 hndl);
+BOOL16   	WINAPI 		mmThreadIsValid16(HANDLE16 hndl);
+BOOL16  	WINAPI 		mmThreadIsCurrent16(HANDLE16 hndl);
+
 #endif /* __WINE_MULTIMEDIA_H */
diff --git a/loader/main.c b/loader/main.c
index 17def50..6880ee7 100644
--- a/loader/main.c
+++ b/loader/main.c
@@ -17,7 +17,6 @@
 #include "main.h"
 #include "menu.h"
 #include "message.h"
-#include "multimedia.h"
 #include "dialog.h"
 #include "drive.h"
 #include "queue.h"
@@ -239,9 +238,6 @@
     /* Initialize cursor/icons */
     CURSORICON_Init();
 
-    /* Initialize multimedia */
-    if (!MULTIMEDIA_Init()) return FALSE;
-
     /* Initialize message spying */
     if (!SPY_Init()) return FALSE;
 
diff --git a/multimedia/audio.c b/multimedia/audio.c
index f613fce..870f269 100644
--- a/multimedia/audio.c
+++ b/multimedia/audio.c
@@ -141,6 +141,9 @@
 	    return MMSYSERR_NOERROR;
 	}
 	break;
+    default:
+	FIXME(wave, "Unknown CB message %u\n", wMsg);
+	break;
     }
     return 0;
 }
@@ -162,7 +165,7 @@
     LPBYTE		lpData;
     int			count;
     audio_buf_info 	abinfo;
-    
+
     for (;;) {
 	/* get number of writable fragments */
 	if (ioctl(wwo->unixdev, SNDCTL_DSP_GETOSPACE, &abinfo) == -1) {
@@ -223,8 +226,10 @@
 	}  else	{
 	    count = write(wwo->unixdev, lpData + wwo->dwOffCurrHdr, wwo->dwRemain);
 	    TRACE(wave, "write(%p[%5lu], %5lu) => %d\n", lpData, wwo->dwOffCurrHdr, wwo->dwRemain, count);
-	    wwo->dwOffCurrHdr += count;
-	    wwo->dwRemain = wwo->dwFragmentSize;
+	    if (count > 0) {
+		wwo->dwOffCurrHdr += wwo->dwRemain;
+		wwo->dwRemain = wwo->dwFragmentSize;
+	    }
 	}
     }
 }
diff --git a/multimedia/init.c b/multimedia/init.c
index af9b1e0..eb5c556 100644
--- a/multimedia/init.c
+++ b/multimedia/init.c
@@ -18,6 +18,7 @@
 
 DECLARE_DEBUG_CHANNEL(mci)
 DECLARE_DEBUG_CHANNEL(midi)
+DECLARE_DEBUG_CHANNEL(mmsys)
 
 #ifdef HAVE_OSS
 
@@ -38,7 +39,7 @@
  *
  */
 #ifdef HAVE_OSS
-int unixToWindowsDeviceType(int type)
+static	int unixToWindowsDeviceType(int type)
 {
 #if !defined(__NetBSD__) && !defined(__OpenBSD__)
     /* MOD_MIDIPORT     output port 
@@ -72,7 +73,7 @@
  * Initializes the MIDI devices information variables
  *
  */
-BOOL MULTIMEDIA_MidiInit(void)
+static	BOOL MULTIMEDIA_MidiInit(void)
 {
 #if defined(HAVE_OSS) && !defined(__NetBSD__) && !defined(__OpenBSD__)
     int 		i, status, numsynthdevs = 255, nummididevs = 255;
@@ -256,10 +257,14 @@
     return TRUE;
 }
 
-BOOL MULTIMEDIA_MciInit(void)
+/**************************************************************************
+ * 			MULTIMEDIA_MciInit			[internal]
+ *
+ * Initializes the MCI internal variables.
+ *
+ */static	BOOL MULTIMEDIA_MciInit(void)
 {
     LPSTR	ptr1, ptr2;
-    char    	buffer[1024];
 
     mciInstalledCount = 0;
     ptr1 = lpmciInstallNames = xmalloc(2048);
@@ -286,25 +291,61 @@
     }
     mciInstalledListLen = ptr1 - lpmciInstallNames;
 
-    if (PROFILE_GetWineIniString("options", "mciExternal", "", buffer, sizeof(buffer)) > 0) {
-	int		i;
- 
-	for (i = 0; MCI_InternalDescriptors[i].uDevType != 0xFFFF; i++) {
-	    if (strstr(buffer, MCI_InternalDescriptors[i].lpstrName) != NULL) {
-		MCI_InternalDescriptors[i].uDevType = 0;	/* disable slot */
+    return TRUE;
+}
+
+HINSTANCE	WINMM_hInstance = 0; 
+HINSTANCE	MMSYSTEM_hInstance = 0; 
+static		bInitDone = FALSE;
+
+/**************************************************************************
+ * 			WINMM_LibMain				[EntryPoint]
+ *
+ * WINMM DLL entry point
+ *
+ */
+BOOL WINAPI WINMM_LibMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
+{
+    TRACE(mmsys, "0x%x 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
+
+    switch (fdwReason) {
+    case DLL_PROCESS_ATTACH:
+	if (!bInitDone) {
+	    if (MULTIMEDIA_MidiInit() && MULTIMEDIA_MciInit()) {
+		bInitDone = TRUE;
+	    } else {
+		return FALSE;
 	    }
 	}
+	WINMM_hInstance = hinstDLL;
+	break;
+    case DLL_THREAD_ATTACH:
+    case DLL_THREAD_DETACH:
+    case DLL_PROCESS_DETACH:
+	break;
     }
     return TRUE;
 }
 
-/**************************************************************************
- * 			MULTIMEDIA_Init			[internal]
- *
- * Initializes the multimedia information variables
- *
- */
-BOOL MULTIMEDIA_Init(void)
+BOOL WINAPI MMSYSTEM_LibMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
 {
-    return MULTIMEDIA_MidiInit() && MULTIMEDIA_MciInit();
+    TRACE(mmsys, "0x%x 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
+
+    switch (fdwReason) {
+    case DLL_PROCESS_ATTACH:
+	if (!bInitDone) {
+	    if (MULTIMEDIA_MidiInit() && MULTIMEDIA_MciInit()) {
+		bInitDone = TRUE;
+	    } else {
+		return FALSE;
+	    }
+	}
+	MMSYSTEM_hInstance = hinstDLL;
+	break;
+    case DLL_THREAD_ATTACH:
+    case DLL_THREAD_DETACH:
+    case DLL_PROCESS_DETACH:
+	break;
+    }
+    return TRUE;
 }
diff --git a/multimedia/mci.c b/multimedia/mci.c
index d78c00d..2bc502d 100644
--- a/multimedia/mci.c
+++ b/multimedia/mci.c
@@ -16,9 +16,9 @@
 #include "mmsystem.h"
 #include "multimedia.h"
 #include "selectors.h"
-#include "debug.h"
 #include "digitalv.h"
 #include "wine/winbase16.h"
+#include "debug.h"
 
 DEFAULT_DEBUG_CHANNEL(mci)
 
@@ -28,6 +28,46 @@
 int	mciInstalledListLen;
 LPSTR	lpmciInstallNames = NULL;
 
+static	struct MCI_StringType {
+    LPCSTR	str;
+    UINT	type;
+} MCI_StringType_List[] = {
+    /* MCI types that are working */
+    {"CDAUDIO", MCI_DEVTYPE_CD_AUDIO},
+    {"WAVEAUDIO", MCI_DEVTYPE_WAVEFORM_AUDIO},
+    {"SEQUENCER", MCI_DEVTYPE_SEQUENCER},
+
+    /* MCI types that should be working */
+    {"ANIMATION1", MCI_DEVTYPE_ANIMATION},
+    {"MPEGVIDEO", MCI_DEVTYPE_DIGITAL_VIDEO},
+    {"AVIVIDEO", MCI_DEVTYPE_DIGITAL_VIDEO},
+
+    /* MCI types not likely to be supported */
+    {"VCR", MCI_DEVTYPE_VCR},
+    {"VIDEODISC", MCI_DEVTYPE_VIDEODISC},
+    {"OVERLAY", MCI_DEVTYPE_OVERLAY},
+    {"DAT", MCI_DEVTYPE_DAT},
+    {"SCANNER", MCI_DEVTYPE_SCANNER},
+
+    {NULL, 0}
+};
+
+WORD	MCI_GetDevTypeFromString(LPCSTR str)
+{
+    struct MCI_StringType*	mst = MCI_StringType_List;
+
+    while (mst->str && strcmp(mst->str, str)) mst++;
+    return mst->type;
+}
+
+LPCSTR	MCI_GetStringFromDevType(WORD type)
+{
+    struct MCI_StringType*	mst = MCI_StringType_List;
+
+    while (mst->str && mst->type != type) mst++;
+    return mst->str;
+}
+
 /* The wDevID's returned by wine were originally in the range 
  * 0 - (MAXMCIDRIVERS - 1) and used directly as array indices.
  * Unfortunately, ms-windows uses wDevID of zero to indicate
@@ -39,73 +79,6 @@
 
 #define MCI_MAGIC 0x0F00
 
-MCI_WineDesc	MCI_InternalDescriptors[] = {
-    {MCI_DEVTYPE_CD_AUDIO,		"CDAUDIO", 	MCICDAUDIO_DriverProc},
-    {MCI_DEVTYPE_WAVEFORM_AUDIO,	"WAVEAUDIO",	MCIWAVE_DriverProc},
-    {MCI_DEVTYPE_SEQUENCER,		"SEQUENCER", 	MCIMIDI_DriverProc},
-    {MCI_DEVTYPE_ANIMATION,		"ANIMATION1", 	MCIANIM_DriverProc},
-    {MCI_DEVTYPE_DIGITAL_VIDEO,		"AVIVIDEO", 	MCIAVI_DriverProc},
-
-    {0xFFFF,				NULL,		NULL}	/* sentinel */
-};
-
-#if 0
-/**************************************************************************
- * 				MCI_GetDevTypeString		[internal]
- */
-static	LPCSTR		MCI_GetDevTypeString(WORD uDevType)
-{
-    LPCSTR	str = "??? MCI ???";
-    int		i;
-
-    for (i = 0; MCI_InternalDescriptors[i].uDevType != 0xFFFF; i++) {
-	if (MCI_InternalDescriptors[i].uDevType != 0 && 
-	    MCI_InternalDescriptors[i].uDevType == uDevType) {
-	    str = MCI_InternalDescriptors[i].lpstrName;
-	    break;
-	}
-    }
-    /*    TRACE(mci, "devType=%u => %s\n", uDevType, str);*/
-    return str;
-}
-#endif
-
-/**************************************************************************
- * 				MCI_GetProc			[internal]
- */
-static	MCIPROC		MCI_GetProc(UINT16 uDevType)
-{
-    MCIPROC	proc = 0;
-    int		i;
-
-    for (i = 0; MCI_InternalDescriptors[i].uDevType != 0xFFFF; i++) {
-	if (MCI_InternalDescriptors[i].uDevType != 0 && 
-	    MCI_InternalDescriptors[i].uDevType == uDevType) {
-	    proc = MCI_InternalDescriptors[i].lpfnProc;
-	    break;
-	}
-    }
-    return proc;
-}
-
-/**************************************************************************
- * 				MCI_GetDevType			[internal]
- */
-WORD		MCI_GetDevType(LPCSTR str)
-{
-    WORD 	uDevType = 0;
-    int		i;
-
-    for (i = 0; MCI_InternalDescriptors[i].uDevType != 0xFFFF; i++) {
-	if (MCI_InternalDescriptors[i].uDevType != 0 && 
-	    strcmp(str, MCI_InternalDescriptors[i].lpstrName) == 0) {
-	    uDevType = MCI_InternalDescriptors[i].uDevType;
-	    break;
-	}
-    }
-    return uDevType;
-}
-
 /**************************************************************************
  * 				MCI_DevIDToIndex		[internal]
  */
@@ -191,10 +164,10 @@
 /**************************************************************************
  * 			MCI_MapMsg16To32A			[internal]
  */
-int	MCI_MapMsg16To32A(WORD uDevType, WORD wMsg, DWORD* lParam)
+MCI_MapType	MCI_MapMsg16To32A(WORD uDevType, WORD wMsg, DWORD* lParam)
 {
     if (*lParam == 0)
-	return 0;
+	return MCI_MAP_OK;
     /* FIXME: to add also (with seg/linear modifications to do):
      * MCI_LIST, MCI_LOAD, MCI_QUALITY, MCI_RESERVE, MCI_RESTORE, MCI_SAVE
      * MCI_SETAUDIO, MCI_SETTUNER, MCI_SETVIDEO
@@ -233,7 +206,7 @@
     case MCI_UPDATE:
     case MCI_WHERE:
 	*lParam = (DWORD)PTR_SEG_TO_LIN(*lParam);
-	return 0;
+	return MCI_MAP_OK;
     case MCI_WINDOW:
 	/* in fact, I would also need the dwFlags... to see 
 	 * which members of lParam are effectively used 
@@ -251,11 +224,11 @@
 		mbp32->nVirtKey = mbp16->nVirtKey;
 		mbp32->hwndBreak = mbp16->hwndBreak;
 	    } else {
-		return -2;
+		return MCI_MAP_NOMEM;
 	    }
 	    *lParam = (DWORD)mbp32;
 	}
-	return 1;
+	return MCI_MAP_OKMEM;
     case MCI_ESCAPE:
 	{
             LPMCI_VD_ESCAPE_PARMSA	mvep32a = HeapAlloc(SystemHeap, 0, sizeof(MCI_VD_ESCAPE_PARMSA));
@@ -265,11 +238,11 @@
 		mvep32a->dwCallback       = mvep16->dwCallback;
 		mvep32a->lpstrCommand     = PTR_SEG_TO_LIN(mvep16->lpstrCommand);
 	    } else {
-		return -2;
+		return MCI_MAP_NOMEM;
 	    }
 	    *lParam = (DWORD)mvep32a;
 	}
-	return 1;
+	return MCI_MAP_OKMEM;
     case MCI_INFO:
 	{
             LPMCI_INFO_PARMSA	mip32a = HeapAlloc(SystemHeap, 0, sizeof(MCI_INFO_PARMSA));
@@ -283,11 +256,11 @@
 		mip32a->lpstrReturn = PTR_SEG_TO_LIN(mip16->lpstrReturn);
 		mip32a->dwRetSize   = mip16->dwRetSize;
 	    } else {
-		return -2;
+		return MCI_MAP_NOMEM;
 	    }
 	    *lParam = (DWORD)mip32a;
 	}
-	return 1;
+	return MCI_MAP_OKMEM;
     case MCI_OPEN:
     case MCI_OPEN_DRIVER:	
 	{
@@ -312,11 +285,11 @@
 		 */
 		memcpy(mop32a + 1, mop16 + 1, 2 * sizeof(DWORD));
 	    } else {
-		return -2;
+		return MCI_MAP_NOMEM;
 	    }
 	    *lParam = (DWORD)mop32a;
 	}
-	return 1;
+	return MCI_MAP_OKMEM;
     case MCI_SYSINFO:
 	{
             LPMCI_SYSINFO_PARMSA	msip32a = HeapAlloc(SystemHeap, 0, sizeof(MCI_SYSINFO_PARMSA));
@@ -329,11 +302,11 @@
 		msip32a->dwNumber         = msip16->dwNumber;
 		msip32a->wDeviceType      = msip16->wDeviceType;
 	    } else {
-		return -2;
+		return MCI_MAP_NOMEM;
 	    }
 	    *lParam = (DWORD)msip32a;
 	}
-	return 1;
+	return MCI_MAP_OKMEM;
     case DRV_LOAD:
     case DRV_ENABLE:
     case DRV_OPEN:
@@ -348,18 +321,18 @@
     case DRV_EXITAPPLICATION:
     case DRV_POWER:
 	FIXME(mci, "This is a hack\n");
-	return 0;
+	return MCI_MAP_OK;
 
     default:
 	WARN(mci, "Don't know how to map msg=%s\n", MCI_CommandToString(wMsg));
     }
-    return -1;
+    return MCI_MAP_MSGERROR;
 }
 
 /**************************************************************************
  * 			MCI_UnMapMsg16To32A			[internal]
  */
-int	MCI_UnMapMsg16To32A(WORD uDevType, WORD wMsg, DWORD lParam)
+MCI_MapType	MCI_UnMapMsg16To32A(WORD uDevType, WORD wMsg, DWORD lParam)
 {
     switch (wMsg) {
 	/* case MCI_CAPTURE */
@@ -394,18 +367,18 @@
     case MCI_UNFREEZE:
     case MCI_UPDATE:
     case MCI_WHERE:
-	return 0;
+	return MCI_MAP_OK;
 
     case MCI_WINDOW:
 	/* FIXME ?? see Map function */
-	return 0;
+	return MCI_MAP_OK;
 
     case MCI_BREAK:
     case MCI_ESCAPE:
     case MCI_INFO:
     case MCI_SYSINFO:
 	HeapFree(SystemHeap, 0, (LPVOID)lParam);
-	return 0;
+	return MCI_MAP_OK;
     case MCI_OPEN:
     case MCI_OPEN_DRIVER:	
 	if (lParam) {
@@ -416,7 +389,7 @@
 	    if (!HeapFree(SystemHeap, 0, (LPVOID)(lParam - sizeof(LPMCI_OPEN_PARMS16))))
 		FIXME(mci, "bad free line=%d\n", __LINE__);
 	}
-	return 0;
+	return MCI_MAP_OK;
     case DRV_LOAD:
     case DRV_ENABLE:
     case DRV_OPEN:
@@ -431,68 +404,13 @@
     case DRV_EXITAPPLICATION:
     case DRV_POWER:
 	FIXME(mci, "This is a hack\n");
-	return 0;
+	return MCI_MAP_OK;
     default:
 	FIXME(mci, "Map/Unmap internal error on msg=%s\n", MCI_CommandToString(wMsg));
     }
-    return -1;
+    return MCI_MAP_MSGERROR;
 }
 
-#if 0
-/**************************************************************************
- * 			MCI_MsgMapper32To16_Create		[internal]
- *
- * Helper for MCI_MapMsg32ATo16. 
- * Maps the 32 bit pointer (*ptr), of size bytes, to an allocated 16 bit segmented pointer.
- * if keep is TRUE, keeps track of in 32 bit ptr in allocated 16 bit area.
- *  1 : ok, some memory allocated
- * -2 : ko, memory problem
- */
-static	int	MCI_MsgMapper32To16_Create(void** ptr, int size, BOOLEAN keep)
-{
-    void*	lp = SEGPTR_ALLOC(sizeof(void**) + size);
-
-    if (!lp) {
-	return -2;
-    }
-    if (keep) {
-	*(void**)lp = *ptr;
-	memcpy((char*)lp + sizeof(void**), *ptr, size);
-	*ptr = (char*)SEGPTR_GET(lp) + sizeof(void**);
-    } else {
-	memcpy((char*)lp, *ptr, size);
-	*ptr = (void*)SEGPTR_GET(lp);
-    }
-    return 1;
-   
-}
-
-/**************************************************************************
- * 			MCI_MsgMapper32To16_Destroy		[internal]
- *
- * Helper for MCI_UnMapMsg32ATo16. 
- */
-static	int	MCI_MsgMapper32To16_Destroy(void* ptr, int size, BOOLEAN kept)
-{
-    if (ptr) {
-	void*	msg16 = PTR_SEG_TO_LIN(ptr);
-	void*	alloc;
-
-	if (kept) {
-	    alloc = (char*)msg16 - sizeof(void**);
-	    memcpy(*(void**)alloc, msg16, size);
-	} else {
-	    alloc = msg16;
-	}
-
-	if (!SEGPTR_FREE(alloc)) {
-	    FIXME(mci, "bad free line=%d\n", __LINE__);
-	} 
-    }	
-    return 0;
-}
-#endif
-
 /*
  * 0000 stop
  * 0001 squeeze   signed 4 bytes to 2 bytes     *( LPINT16)D = ( INT16)*( LPINT16)S; D += 2;     S += 4
@@ -505,7 +423,7 @@
  */
 
 /**************************************************************************
- * 			MCI_MsgMapper32To16_CreateV2		[internal]
+ * 			MCI_MsgMapper32To16_Create		[internal]
  *
  * Helper for MCI_MapMsg32ATo16. 
  * Maps the 32 bit pointer (*ptr), of size bytes, to an allocated 16 bit 
@@ -513,16 +431,14 @@
  * map contains a list of action to be performed for the mapping (see list
  * above)
  * if keep is TRUE, keeps track of in 32 bit ptr in allocated 16 bit area.
- *  1 : ok, some memory allocated
- * -2 : ko, memory problem
  */
-static	int	MCI_MsgMapper32To16_CreateV2(void** ptr, int size16, DWORD map, BOOLEAN keep)
+static	MCI_MapType	MCI_MsgMapper32To16_Create(void** ptr, int size16, DWORD map, BOOLEAN keep)
 {
     void*	lp = SEGPTR_ALLOC((keep ? sizeof(void**) : 0) + size16);
     LPBYTE	p16, p32;
 
     if (!lp) {
-	return -2;
+	return MCI_MAP_NOMEM;
     }
     p32 = (LPBYTE)(*ptr);
     if (keep) {
@@ -562,15 +478,15 @@
 	if (size16 != 0) /* DEBUG only */
 	    FIXME(mci, "Mismatch between 16 bit struct size and map nibbles serie\n");
     }
-    return 1;
+    return MCI_MAP_OKMEM;
 }
 
 /**************************************************************************
- * 			MCI_MsgMapper32To16_DestroyV2		[internal]
+ * 			MCI_MsgMapper32To16_Destroy		[internal]
  *
  * Helper for MCI_UnMapMsg32ATo16. 
  */
-static	int	MCI_MsgMapper32To16_DestroyV2(void* ptr, int size16, DWORD map, BOOLEAN kept)
+static	MCI_MapType	MCI_MsgMapper32To16_Destroy(void* ptr, int size16, DWORD map, BOOLEAN kept)
 {
     if (ptr) {
 	void*		msg16 = PTR_SEG_TO_LIN(ptr);
@@ -619,26 +535,22 @@
 	    FIXME(mci, "bad free line=%d\n", __LINE__);
 	} 
     }	
-    return 0;
+    return MCI_MAP_OK;
 }
 
 /**************************************************************************
  * 			MCI_MapMsg32ATo16			[internal]
  *
  * Map a 32-A bit MCI message to a 16 bit MCI message.
- *  1 : ok, some memory allocated, need to call MCI_UnMapMsg32ATo16
- *  0 : ok, no memory allocated
- * -1 : ko, unknown message
- * -2 : ko, memory problem
  */
-int	MCI_MapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD* lParam)
+MCI_MapType	MCI_MapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD* lParam)
 {
     int		size;
     BOOLEAN     keep = FALSE;
     DWORD	map = 0;
 
     if (*lParam == 0)
-	return 0;
+	return MCI_MAP_OK;
 
     /* FIXME: to add also (with seg/linear modifications to do):
      * MCI_LIST, MCI_LOAD, MCI_QUALITY, MCI_RESERVE, MCI_RESTORE, MCI_SAVE
@@ -656,7 +568,7 @@
     case MCI_CUE:
 	switch (uDevType) {
 	case MCI_DEVTYPE_DIGITAL_VIDEO:	size = sizeof(MCI_DGV_CUE_PARMS);	break;
-	case MCI_DEVTYPE_VCR:		/*size = sizeof(MCI_VCR_CUE_PARMS);	break;*/	FIXME(mci, "NIY vcr\n");	return -2;
+	case MCI_DEVTYPE_VCR:		/*size = sizeof(MCI_VCR_CUE_PARMS);	break;*/	FIXME(mci, "NIY vcr\n");	return MCI_MAP_NOMEM;
 	default:			size = sizeof(MCI_GENERIC_PARMS);	break;
 	}
 	break;
@@ -703,11 +615,11 @@
 		    ((LPMCI_DGV_INFO_PARMS16)mip16)->dwItem = ((LPMCI_DGV_INFO_PARMSA)mip32a)->dwItem;
 		}
 	    } else {
-		return -2;
+		return MCI_MAP_NOMEM;
 	    }
 	    *lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_INFO_PARMSA);
 	}
-	return 1;
+	return MCI_MAP_OKMEM;
 	/* case MCI_MARK: */
 	/* case MCI_MONITOR: */
     case MCI_OPEN:
@@ -759,11 +671,11 @@
 		 */
 		memcpy(mop16 + 1, mop32a + 1, 2 * sizeof(DWORD));
 	    } else {
-		return -2;
+		return MCI_MAP_NOMEM;
 	    }
 	    *lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_OPEN_PARMSA);
 	}
-	return 1;
+	return MCI_MAP_OKMEM;
 	/* case MCI_PASTE:*/
     case MCI_PAUSE:
 	size = sizeof(MCI_GENERIC_PARMS);
@@ -784,7 +696,7 @@
     case MCI_RECORD:
 	switch (uDevType) {
 	case MCI_DEVTYPE_DIGITAL_VIDEO:	size = sizeof(MCI_DGV_RECORD_PARMS16);	map = 0x0F1111FB;	break;
-	case MCI_DEVTYPE_VCR:		/*size = sizeof(MCI_VCR_RECORD_PARMS);	break;*/FIXME(mci, "NIY vcr\n");	return -2;
+	case MCI_DEVTYPE_VCR:		/*size = sizeof(MCI_VCR_RECORD_PARMS);	break;*/FIXME(mci, "NIY vcr\n");	return MCI_MAP_NOMEM;
 	default:			size = sizeof(MCI_RECORD_PARMS);	break;
 	}
 	break;
@@ -793,14 +705,14 @@
 	break;
     case MCI_SEEK:
 	switch (uDevType) {
-	case MCI_DEVTYPE_VCR:		/*size = sizeof(MCI_VCR_SEEK_PARMS);	break;*/FIXME(mci, "NIY vcr\n");	return -2;
+	case MCI_DEVTYPE_VCR:		/*size = sizeof(MCI_VCR_SEEK_PARMS);	break;*/FIXME(mci, "NIY vcr\n");	return MCI_MAP_NOMEM;
 	default:			size = sizeof(MCI_SEEK_PARMS);		break;
 	}
 	break;
     case MCI_SET:
 	switch (uDevType) {
 	case MCI_DEVTYPE_DIGITAL_VIDEO:	size = sizeof(MCI_DGV_SET_PARMS);	break;
-	case MCI_DEVTYPE_VCR:		/*size = sizeof(MCI_VCR_SET_PARMS);	break;*/FIXME(mci, "NIY vcr\n");	return -2;
+	case MCI_DEVTYPE_VCR:		/*size = sizeof(MCI_VCR_SET_PARMS);	break;*/FIXME(mci, "NIY vcr\n");	return MCI_MAP_NOMEM;
 	case MCI_DEVTYPE_SEQUENCER:	size = sizeof(MCI_SEQ_SET_PARMS);	break;
         /* FIXME: normally the 16 and 32 bit structures are byte by byte aligned, 
 	 * so not doing anything should work...
@@ -823,14 +735,14 @@
 	 * Assuming solution 2: provided by MCI driver, so zeroing on entry
 	 */
 	case MCI_DEVTYPE_DIGITAL_VIDEO:	size = sizeof(MCI_DGV_STATUS_PARMS16);	map = 0x0B6FF;		break;
-	case MCI_DEVTYPE_VCR:		/*size = sizeof(MCI_VCR_STATUS_PARMS);	break;*/FIXME(mci, "NIY vcr\n");	return -2;
+	case MCI_DEVTYPE_VCR:		/*size = sizeof(MCI_VCR_STATUS_PARMS);	break;*/FIXME(mci, "NIY vcr\n");	return MCI_MAP_NOMEM;
 	default:			size = sizeof(MCI_STATUS_PARMS);	break;
 	}
 	break;
     case MCI_STEP:
 	switch (uDevType) {
 	case MCI_DEVTYPE_DIGITAL_VIDEO:	size = sizeof(MCI_DGV_STEP_PARMS);	break;
-	case MCI_DEVTYPE_VCR:		/*size = sizeof(MCI_VCR_STEP_PARMS);	break;*/FIXME(mci, "NIY vcr\n");	return -2;
+	case MCI_DEVTYPE_VCR:		/*size = sizeof(MCI_VCR_STEP_PARMS);	break;*/FIXME(mci, "NIY vcr\n");	return MCI_MAP_NOMEM;
 	case MCI_DEVTYPE_VIDEODISC:	size = sizeof(MCI_VD_STEP_PARMS);	break;
 	default:			size = sizeof(MCI_GENERIC_PARMS);	break;
 	}
@@ -854,11 +766,11 @@
 		msip16->dwNumber         = msip32a->dwNumber;
 		msip16->wDeviceType      = msip32a->wDeviceType;
 	    } else {
-		return -2;
+		return MCI_MAP_NOMEM;
 	    }
 	    *lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_SYSINFO_PARMSA);
 	}
-	return 1;
+	return MCI_MAP_OKMEM;
 	/* case MCI_UNDO: */
     case MCI_UNFREEZE:
 	switch (uDevType) {
@@ -900,20 +812,19 @@
     case DRV_EXITSESSION:
     case DRV_EXITAPPLICATION:
     case DRV_POWER:
-	FIXME(mci, "This is a hack\n");
-	return 0;
+	return MCI_MAP_PASS;
 
     default:
 	WARN(mci, "Don't know how to map msg=%s\n", MCI_CommandToString(wMsg));
-	return -1;
+	return MCI_MAP_MSGERROR;
     }
-    return MCI_MsgMapper32To16_CreateV2((void**)lParam, size, map, keep);
+    return MCI_MsgMapper32To16_Create((void**)lParam, size, map, keep);
 }
 
 /**************************************************************************
  * 			MCI_UnMapMsg32ATo16			[internal]
  */
-int	MCI_UnMapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD lParam)
+MCI_MapType	MCI_UnMapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD lParam)
 {
     int		size = 0;
     BOOLEAN     kept = FALSE;	/* there is no need to compute size when kept is FALSE */
@@ -951,7 +862,7 @@
 	    if (!SEGPTR_FREE((char*)mip16 - sizeof(LPMCI_INFO_PARMSA)))
 		FIXME(mci, "bad free line=%d\n", __LINE__);
 	}
-	return 0;
+	return MCI_MAP_OK;
 	/* case MCI_MARK: */
 	/* case MCI_MONITOR: */
     case MCI_OPEN:
@@ -976,7 +887,7 @@
 	    if (!SEGPTR_FREE((char*)mop16 - sizeof(LPMCI_OPEN_PARMSA)))
 		FIXME(mci, "bad free line=%d\n", __LINE__);
 	}
-	return 0;
+	return MCI_MAP_OK;
 	/* case MCI_PASTE:*/
     case MCI_PAUSE:
 	break;
@@ -1019,11 +930,11 @@
 		if (!SEGPTR_FREE((char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA)))
 		    FIXME(mci, "bad free line=%d\n", __LINE__);
 	    } else {
-		return -2;
+		return MCI_MAP_NOMEM;
 	    }
 	}
-	return 1;
-	case MCI_DEVTYPE_VCR:		/*size = sizeof(MCI_VCR_STATUS_PARMS);	break;*/FIXME(mci, "NIY vcr\n");	return -2;
+	return MCI_MAP_OKMEM;
+	case MCI_DEVTYPE_VCR:		/*size = sizeof(MCI_VCR_STATUS_PARMS);	break;*/FIXME(mci, "NIY vcr\n");	return MCI_MAP_NOMEM;
 	default:			size = sizeof(MCI_STATUS_PARMS);	break;
 	}
 	break;
@@ -1045,10 +956,10 @@
 		if (!SEGPTR_FREE((char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSA)))
 		    FIXME(mci, "bad free line=%d\n", __LINE__);
 	    } else {
-		return -2;
+		return MCI_MAP_NOMEM;
 	    }
 	}
-	return 1;
+	return MCI_MAP_OKMEM;
 	/* case MCI_UNDO: */
     case MCI_UNFREEZE:
 	break;
@@ -1084,63 +995,101 @@
     case DRV_EXITAPPLICATION:
     case DRV_POWER:
 	FIXME(mci, "This is a hack\n");
-	return 0;
+	return MCI_MAP_PASS;
     default:
 	FIXME(mci, "Map/Unmap internal error on msg=%s\n", MCI_CommandToString(wMsg));
-	return -1;
+	return MCI_MAP_MSGERROR;
     }
-    return MCI_MsgMapper32To16_DestroyV2((void*)lParam, size, map, kept);
+    return MCI_MsgMapper32To16_Destroy((void*)lParam, size, map, kept);
 }
 
 /**************************************************************************
- * 			MCI_SendCommand				[internal]
+ * 			MCI_SendCommandFrom32			[internal]
  */
-DWORD MCI_SendCommand(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
+DWORD MCI_SendCommandFrom32(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
 {
     DWORD		dwRet = MCIERR_DEVICE_NOT_INSTALLED;
     
     if (!MCI_DevIDValid(wDevID)) {
 	dwRet = MCIERR_INVALID_DEVICE_ID;
     } else {
-	MCIPROC		proc = MCI_GetProc(MCI_GetDrv(wDevID)->modp.wType);
-	
-	if (proc) {
-	    dwRet = (*proc)(MCI_GetDrv(wDevID)->modp.wDeviceID, 
-			    MCI_GetDrv(wDevID)->hDrv, 
-			    wMsg, dwParam1, dwParam2);
-	} else if (MCI_GetDrv(wDevID)->hDrv) {
-	    switch (DRIVER_GetType(MCI_GetDrv(wDevID)->hDrv)) {
-	    case WINE_DI_TYPE_16:
-		{
-		    int			res;
-		    
-		    switch (res = MCI_MapMsg32ATo16(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam1, &dwParam2)) {
-		    case -1:
-			TRACE(mci, "Not handled yet (%s)\n", MCI_CommandToString(wMsg));
-			dwRet = MCIERR_DRIVER_INTERNAL;
-			break;
-		    case -2:
-			TRACE(mci, "Problem mapping msg=%s from 32a to 16\n", MCI_CommandToString(wMsg));
-			dwRet = MCIERR_OUT_OF_MEMORY;
-			break;
-		    case 0:
-		    case 1:
-			dwRet = SendDriverMessage16(MCI_GetDrv(wDevID)->hDrv, wMsg, dwParam1, dwParam2);
-			if (res)
-			    MCI_UnMapMsg32ATo16(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam1, dwParam2);
-			break;
-		    }
+	switch (DRIVER_GetType(MCI_GetDrv(wDevID)->hDrv)) {
+	case WINE_DI_TYPE_16:
+	    {
+		MCI_MapType	res;
+		
+		switch (res = MCI_MapMsg32ATo16(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam1, &dwParam2)) {
+		case MCI_MAP_MSGERROR:
+		    TRACE(mci, "Not handled yet (%s)\n", MCI_CommandToString(wMsg));
+		    dwRet = MCIERR_DRIVER_INTERNAL;
+		    break;
+		case MCI_MAP_NOMEM:
+		    TRACE(mci, "Problem mapping msg=%s from 32a to 16\n", MCI_CommandToString(wMsg));
+		    dwRet = MCIERR_OUT_OF_MEMORY;
+		    break;
+		case MCI_MAP_OK:
+		case MCI_MAP_OKMEM:
+		    dwRet = SendDriverMessage16(MCI_GetDrv(wDevID)->hDrv, wMsg, dwParam1, dwParam2);
+		    if (res ==  MCI_MAP_OKMEM)
+			MCI_UnMapMsg32ATo16(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam1, dwParam2);
+		    break;
+		case MCI_MAP_PASS:
+		    dwRet = SendDriverMessage(MCI_GetDrv(wDevID)->hDrv, wMsg, dwParam1, dwParam2);
+		    break;
 		}
-		break;
-	    case WINE_DI_TYPE_32:
-		dwRet = SendDriverMessage(MCI_GetDrv(wDevID)->hDrv, wMsg, dwParam1, dwParam2);
-		break;
-	    default:
-		WARN(mci, "Unknown driver type=%u\n", DRIVER_GetType(MCI_GetDrv(wDevID)->hDrv));
-		dwRet = MCIERR_DRIVER_INTERNAL;
 	    }
-	} else {
-	    WARN(mci, "unknown device type=%04X !\n", MCI_GetDrv(wDevID)->modp.wType);
+	    break;
+	case WINE_DI_TYPE_32:
+	    dwRet = SendDriverMessage(MCI_GetDrv(wDevID)->hDrv, wMsg, dwParam1, dwParam2);
+	    break;
+	default:
+	    WARN(mci, "Unknown driver type=%u\n", DRIVER_GetType(MCI_GetDrv(wDevID)->hDrv));
+	    dwRet = MCIERR_DRIVER_INTERNAL;
+	}
+    }
+    return dwRet;
+}
+
+/**************************************************************************
+ * 			MCI_SendCommandFrom16			[internal]
+ */
+DWORD MCI_SendCommandFrom16(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
+{
+    DWORD		dwRet = MCIERR_DEVICE_NOT_INSTALLED;
+    
+    if (!MCI_DevIDValid(wDevID)) {
+	dwRet = MCIERR_INVALID_DEVICE_ID;
+    } else {
+	MCI_MapType		res;
+	
+	switch (DRIVER_GetType(MCI_GetDrv(wDevID)->hDrv)) {
+	case WINE_DI_TYPE_16:		
+	    dwRet = SendDriverMessage16(MCI_GetDrv(wDevID)->hDrv, wMsg, dwParam1, dwParam2);
+	    break;
+	case WINE_DI_TYPE_32:
+	    switch (res = MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2)) {
+	    case MCI_MAP_MSGERROR:
+		TRACE(mci, "Not handled yet (%s)\n", MCI_CommandToString(wMsg));
+		dwRet = MCIERR_DRIVER_INTERNAL;
+		break;
+	    case MCI_MAP_NOMEM:
+		TRACE(mci, "Problem mapping msg=%s from 16 to 32a\n", MCI_CommandToString(wMsg));
+		dwRet = MCIERR_OUT_OF_MEMORY;
+		break;
+	    case MCI_MAP_OK:
+	    case MCI_MAP_OKMEM:
+		dwRet = SendDriverMessage(wDevID, wMsg, dwParam1, dwParam2);
+		if (res == MCI_MAP_OKMEM)
+		    MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
+		break;
+	    case MCI_MAP_PASS:
+		dwRet = SendDriverMessage16(MCI_GetDrv(wDevID)->hDrv, wMsg, dwParam1, dwParam2);
+		break;
+	    }
+	    break;
+	default:
+	    WARN(mci, "Unknown driver type=%u\n", DRIVER_GetType(MCI_GetDrv(wDevID)->hDrv));
+	    dwRet = MCIERR_DRIVER_INTERNAL;
 	}
     }
     return dwRet;
@@ -1151,16 +1100,19 @@
  */
 DWORD MCI_Open(DWORD dwParam, LPMCI_OPEN_PARMSA lpParms)
 {
-    char		strDevTyp[128];
-    UINT16		uDevType = 0;
-    UINT16		wDevID = MCI_FirstDevID();
-    DWORD 		dwRet;
-    
+    char			strDevTyp[128];
+    UINT16			uDevType = 0;
+    UINT16			wDevID = MCI_FirstDevID();
+    DWORD 			dwRet; 
+    HDRVR			hDrv;
+    MCI_OPEN_DRIVER_PARMSA	modp;
+	    
+   
     TRACE(mci, "(%08lX, %p)\n", dwParam, lpParms);
     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
     
     if ((dwParam & ~(MCI_OPEN_SHAREABLE|MCI_OPEN_ELEMENT|MCI_OPEN_ALIAS|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_NOTIFY|MCI_WAIT)) != 0) {
-	FIXME(mci, "unsupported yet dwFlags=%08lX\n", 
+	FIXME(mci, "Unsupported yet dwFlags=%08lX\n", 
 	      (dwParam & ~(MCI_OPEN_SHAREABLE|MCI_OPEN_ELEMENT|MCI_OPEN_ALIAS|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_NOTIFY|MCI_WAIT)));
     }
 
@@ -1218,7 +1170,6 @@
 	    if (lpParms->lpstrDeviceType == NULL) 
 		return MCIERR_NULL_PARAMETER_BLOCK;
 	    TRACE(mci, "Dev='%s' !\n", lpParms->lpstrDeviceType);
-	    /* FIXME is there any memory leak here ? */
 	    strcpy(strDevTyp, lpParms->lpstrDeviceType);
 	}
     }
@@ -1229,36 +1180,27 @@
     }
 
     CharUpperA(strDevTyp);
-
-    /* try Wine internal MCI drivers */
-    uDevType = MCI_GetDevType(strDevTyp);
-    if (uDevType == 0) { /* Nope, load external */
-	HDRVR			hDrv;
-	MCI_OPEN_DRIVER_PARMSA	modp;
-	    
-	modp.wDeviceID = wDevID;
-	modp.lpstrParams = NULL;
-	
-	/* FIXME: this is a hack... some MCI drivers, while being open, call
-	 * mciSetData, which lookup for non empty slots in MCI table list
-	 * Unfortunatly, open slots are known when wType == 0...
-	 * so use a dummy type, just to keep on going. May be wType == 0 is 
-	 * not the best solution to indicate empty slot in MCI drivers table
-	 */
-	MCI_GetDrv(wDevID)->modp.wType = MCI_DEVTYPE_CD_AUDIO;
-	hDrv = OpenDriverA(strDevTyp, "mci", (LPARAM)&modp);
-	
-	if (!hDrv) {
-	    FIXME(mci, "Couldn't load driver for type %s.\n", strDevTyp);
-	    return MCIERR_DEVICE_NOT_INSTALLED;
-	}				
-	uDevType = modp.wType;
-	MCI_GetDrv(wDevID)->hDrv = hDrv;
-	
-	TRACE(mci, "Loaded driver %u (%s), type is %d\n", hDrv, strDevTyp, uDevType);
-    } else {
-	MCI_GetDrv(wDevID)->hDrv = 0;
-    }
+    
+    modp.wDeviceID = wDevID;
+    modp.lpstrParams = NULL;
+    
+    /* FIXME: this is a hack... some MCI drivers, while being open, call
+     * mciSetData, which lookup for non empty slots in MCI table list
+     * Unfortunatly, open slots are known when wType == 0...
+     * so use a dummy type, just to keep on going. May be wType == 0 is 
+     * not the best solution to indicate empty slot in MCI drivers table
+     */
+    MCI_GetDrv(wDevID)->modp.wType = MCI_DEVTYPE_CD_AUDIO;
+    hDrv = OpenDriverA(strDevTyp, "mci", (LPARAM)&modp);
+    
+    if (!hDrv) {
+	FIXME(mci, "Couldn't load driver for type %s.\n", strDevTyp);
+	return MCIERR_DEVICE_NOT_INSTALLED;
+    }				
+    uDevType = modp.wType;
+    MCI_GetDrv(wDevID)->hDrv = hDrv;
+    
+    TRACE(mci, "Loaded driver %u (%s), type is %d\n", hDrv, strDevTyp, uDevType);
     
     MCI_GetDrv(wDevID)->mop.lpstrDeviceType = strdup(strDevTyp);
     MCI_GetDrv(wDevID)->modp.wType = uDevType;
@@ -1269,16 +1211,18 @@
     TRACE(mci, "mcidev=%d, uDevType=%04X wDeviceID=%04X !\n", 
 	  wDevID, uDevType, lpParms->wDeviceID);
 
-    dwRet = MCI_SendCommand(wDevID, MCI_OPEN_DRIVER, dwParam, (DWORD)lpParms);
     MCI_GetDrv(wDevID)->lpfnYieldProc = MCI_DefYieldProc;
     MCI_GetDrv(wDevID)->dwYieldData = VK_CANCEL;
     MCI_GetDrv(wDevID)->hCreatorTask = GetCurrentTask();
+    MCI_GetDrv(wDevID)->dwPrivate = 0;
     
+    dwRet = MCI_SendCommandFrom32(wDevID, MCI_OPEN_DRIVER, dwParam, (DWORD)lpParms);
+
     if (dwRet == 0) {
 	/* only handled devices fall through */
 	TRACE(mci, "wDevID = %04X wDeviceID = %d dwRet = %ld\n", wDevID, lpParms->wDeviceID, dwRet);
     } else {
-	TRACE(mci, "failed to open driver (MCI_OPEN_DRIVER msg) [%08lx], closing\n", dwRet);
+	TRACE(mci, "Failed to open driver (MCI_OPEN_DRIVER msg) [%08lx], closing\n", dwRet);
 	MCI_GetDrv(wDevID)->modp.wType = 0;
     }
     if (dwParam & MCI_NOTIFY)
@@ -1301,9 +1245,9 @@
 	return MCIERR_CANNOT_USE_ALL;
     }
 
-    dwRet = MCI_SendCommand(wDevID, MCI_CLOSE_DRIVER, dwParam, (DWORD)lpParms);
+    dwRet = MCI_SendCommandFrom32(wDevID, MCI_CLOSE_DRIVER, dwParam, (DWORD)lpParms);
     if (MCI_GetDrv(wDevID)->hDrv) {
-#if 0
+#if 1
 	CloseDriver(MCI_GetDrv(wDevID)->hDrv, 0, 0);
 #endif
     }
diff --git a/multimedia/mcianim.c b/multimedia/mcianim.c
index 9c40845..993a281 100644
--- a/multimedia/mcianim.c
+++ b/multimedia/mcianim.c
@@ -26,11 +26,12 @@
 #define SECONDS_PERMIN	 	60
 
 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 */
-	MCI_OPEN_PARMSA 	openParms;
+        UINT16		wDevID;
+        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 */
+	MCI_OPEN_PARMSA openParms;
 	DWORD		dwTimeFormat;
 	int		mode;
 	UINT16		nCurTrack;
@@ -41,20 +42,69 @@
 	LPDWORD		lpdwTrackPos;
 } WINE_MCIANIM;
 
-static WINE_MCIANIM	AnimDev[MAX_ANIMDRV];
+static WINE_MCIANIM	MCIAnimDev[MAX_ANIMDRV];
 
 /*-----------------------------------------------------------------------*/
 
 /**************************************************************************
+ * 				ANIM_drvGetDrv			[internal]	
+ */
+static WINE_MCIANIM*  ANIM_drvGetDrv(UINT16 wDevID)
+{
+    int	i;
+
+    for (i = 0; i < MAX_ANIMDRV; i++) {
+	if (MCIAnimDev[i].wDevID == wDevID) {
+	    return &MCIAnimDev[i];
+	}
+    }
+    return 0;
+}
+
+/**************************************************************************
+ * 				ANIM_drvOpen			[internal]	
+ */
+static	DWORD	ANIM_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
+{
+    int	i;
+
+    for (i = 0; i < MAX_ANIMDRV; i++) {
+	if (MCIAnimDev[i].wDevID == 0) {
+	    MCIAnimDev[i].wDevID = modp->wDeviceID;
+	    modp->wCustomCommandTable = -1;
+	    modp->wType = MCI_DEVTYPE_CD_AUDIO;
+	    return modp->wDeviceID;
+	}
+    }
+    return 0;
+}
+
+/**************************************************************************
+ * 				ANIM_drvClose		[internal]	
+ */
+static	DWORD	ANIM_drvClose(DWORD dwDevID)
+{
+    WINE_MCIANIM*  wma = ANIM_drvGetDrv(dwDevID);
+
+    if (wma) {
+	wma->wDevID = 0;
+	return 1;
+    }
+    return 0;
+}
+
+/**************************************************************************
  * 				ANIM_mciGetOpenDrv		[internal]	
  */
 static WINE_MCIANIM*  ANIM_mciGetOpenDrv(UINT16 wDevID)
 {
-    if (wDevID >= MAX_ANIMDRV || AnimDev[wDevID].nUseCount == 0) {
+    WINE_MCIANIM*	wma = ANIM_drvGetDrv(wDevID);
+    
+    if (wma == NULL || wma->nUseCount == 0) {
 	WARN(mcianim, "Invalid wDevID=%u\n", wDevID);
 	return 0;
     }
-    return &AnimDev[wDevID];
+    return wma;
 }
 
 /**************************************************************************
@@ -63,15 +113,13 @@
 static DWORD ANIM_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_OPEN_PARMSA lpOpenParms)
 {
     DWORD		dwDeviceID;
-    WINE_MCIANIM*	wma;
-
+    WINE_MCIANIM*	wma = ANIM_drvGetDrv(wDevID);
+    
     TRACE(mcianim,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpOpenParms);
-
-    if (lpOpenParms == NULL) return MCIERR_INTERNAL;
-    if (wDevID >= MAX_ANIMDRV)	return MCIERR_INVALID_DEVICE_ID;
-
-    wma = &AnimDev[wDevID];
-
+    
+    if (lpOpenParms == NULL) 	return MCIERR_INTERNAL;
+    if (wma == NULL)		return MCIERR_INVALID_DEVICE_ID;
+    
     if (wma->nUseCount > 0) {
 	/* The driver already open on this channel */
 	/* If the driver was opened shareable before and this open specifies */
@@ -84,13 +132,13 @@
 	wma->nUseCount = 1;
 	wma->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
     }
-
+    
     dwDeviceID = lpOpenParms->wDeviceID;
-
+    
     TRACE(mcianim,"wDevID=%04X\n", wDevID);
     /* FIXME this is not consistent with other implementations */
     lpOpenParms->wDeviceID = wDevID;
-
+    
     /*TRACE(mcianim,"lpParms->wDevID=%04X\n", lpParms->wDeviceID);*/
     if (dwFlags & MCI_OPEN_ELEMENT) {
 	TRACE(mcianim,"MCI_OPEN_ELEMENT '%s' !\n", lpOpenParms->lpstrElementName);
@@ -126,11 +174,11 @@
 static DWORD ANIM_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
 {
     WINE_MCIANIM*	wma = ANIM_mciGetOpenDrv(wDevID);
-
+    
     TRACE(mcianim,"(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
-
+    
     if (wma == NULL)	 return MCIERR_INVALID_DEVICE_ID;
-
+    
     if (--wma->nUseCount == 0) {
 	if (wma->lpdwTrackLen != NULL) free(wma->lpdwTrackLen);
 	if (wma->lpdwTrackPos != NULL) free(wma->lpdwTrackPos);
@@ -145,12 +193,12 @@
 				LPMCI_GETDEVCAPS_PARMS lpParms)
 {
     WINE_MCIANIM*	wma = ANIM_mciGetOpenDrv(wDevID);
-
+    
     TRACE(mcianim,"(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-
+    
     if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
     if (wma == NULL)	 return MCIERR_INVALID_DEVICE_ID;
-
+    
     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
 	TRACE(mcianim, "MCI_GETDEVCAPS_ITEM dwItem=%08lX;\n", lpParms->dwItem);
 	switch(lpParms->dwItem) {
@@ -247,7 +295,7 @@
 {
     DWORD	dwFrame = 0;
     UINT16	wTrack;
-
+    
     TRACE(mcianim,"(%p, %08lX, %lu);\n", wma, dwFormatType, dwTime);
     
     switch (dwFormatType) {
@@ -291,37 +339,37 @@
     WINE_MCIANIM*	wma = ANIM_mciGetOpenDrv(wDevID);
     DWORD		ret = 0;
     LPSTR		str = 0;
-
+    
     TRACE(mcianim,"(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-
+    
     if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
 	ret = MCIERR_NULL_PARAMETER_BLOCK;
     } else if (wma == NULL) {
 	ret = MCIERR_INVALID_DEVICE_ID;
     } else {
 	TRACE(mcianim, "buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
-
-    switch(dwFlags) {
-    case MCI_INFO_PRODUCT:
+	
+	switch(dwFlags) {
+	case MCI_INFO_PRODUCT:
 	    str = "Wine's animation";
-	break;
-    case MCI_INFO_FILE:
+	    break;
+	case MCI_INFO_FILE:
 	    str = wma->openParms.lpstrElementName;
-	break;
-    case MCI_ANIM_INFO_TEXT:
+	    break;
+	case MCI_ANIM_INFO_TEXT:
 	    str = "Animation Window";
-	break;
-    default:
+	    break;
+	default:
 	    WARN(mcianim, "Don't know this info command (%lu)\n", dwFlags);
 	    ret = MCIERR_UNRECOGNIZED_COMMAND;
-    }
+	}
     }
     if (str) {
 	ret = MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, str);
     } else {
 	lpParms->lpstrReturn[0] = 0;
     }
-
+    
     return ret;
 }
 
@@ -331,12 +379,12 @@
 static DWORD ANIM_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
 {
     WINE_MCIANIM*	wma = ANIM_mciGetOpenDrv(wDevID);
-
+    
     TRACE(mcianim,"(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-
+    
     if (lpParms == NULL) return MCIERR_INTERNAL;
     if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
-
+    
     if (dwFlags & MCI_NOTIFY) {
 	TRACE(mcianim, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 	      lpParms->dwCallback);
@@ -418,12 +466,12 @@
 {
     WINE_MCIANIM*	wma = ANIM_mciGetOpenDrv(wDevID);
     int 	start, end;
-
+    
     TRACE(mcianim,"(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-
+    
     if (lpParms == NULL) return MCIERR_INTERNAL;
     if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
-
+    
     start = 0; 		end = wma->dwTotalLen;
     wma->nCurTrack = 1;
     if (dwFlags & MCI_FROM) {
@@ -450,18 +498,18 @@
 static DWORD ANIM_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
 {
     WINE_MCIANIM*	wma = ANIM_mciGetOpenDrv(wDevID);
-
+    
     TRACE(mcianim,"(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-
+    
     if (lpParms == NULL) return MCIERR_INTERNAL;
     if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
-
+    
     wma->mode = MCI_MODE_STOP;
     if (dwFlags & MCI_NOTIFY) {
 	TRACE(mcianim, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 	      lpParms->dwCallback);
 	mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
-			wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			  wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
     }
     return 0;
 }
@@ -472,7 +520,7 @@
 static DWORD ANIM_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
 {
     WINE_MCIANIM*	wma = ANIM_mciGetOpenDrv(wDevID);
-
+    
     TRACE(mcianim,"(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
     if (lpParms == NULL) return MCIERR_INTERNAL;
     wma->mode = MCI_MODE_PAUSE;
@@ -480,7 +528,7 @@
 	TRACE(mcianim, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 	      lpParms->dwCallback);
 	mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
-			wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			  wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
     }
     return 0;
 }
@@ -491,7 +539,7 @@
 static DWORD ANIM_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
 {
     WINE_MCIANIM*	wma = ANIM_mciGetOpenDrv(wDevID);
-
+    
     TRACE(mcianim,"(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
     if (lpParms == NULL) return MCIERR_INTERNAL;
     wma->mode = MCI_MODE_STOP;
@@ -499,7 +547,7 @@
 	TRACE(mcianim, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 	      lpParms->dwCallback);
 	mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
-			wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			  wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
     }
     return 0;
 }
@@ -512,9 +560,9 @@
     WINE_MCIANIM*	wma = ANIM_mciGetOpenDrv(wDevID);
     DWORD	dwRet;
     MCI_PLAY_PARMS PlayParms;
-
+    
     TRACE(mcianim,"(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-
+    
     if (lpParms == NULL) return MCIERR_INTERNAL;
     wma->mode = MCI_MODE_SEEK;
     switch(dwFlags) {
@@ -535,7 +583,7 @@
 	TRACE(mcianim, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 	      lpParms->dwCallback);
 	mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
-			wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			  wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
     }
     return dwRet;
 }
@@ -547,7 +595,7 @@
 static DWORD ANIM_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
 {
     WINE_MCIANIM*	wma = ANIM_mciGetOpenDrv(wDevID);
-
+    
     TRACE(mcianim,"(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
     if (lpParms == NULL) return MCIERR_INTERNAL;
     if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
@@ -579,29 +627,29 @@
 	TRACE(mcianim, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
 	      lpParms->dwCallback);
 	mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
-			wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
+			  wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
     }
     return 0;
 }
 
 /**************************************************************************
- * 				ANIM_DriverProc32		[sample driver]
+ * 				ANIM_DriverProc			[sample driver]
  */
-LONG MCIANIM_DriverProc(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
-		       DWORD dwParam1, DWORD dwParam2)
+LONG MCIANIM_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
+			DWORD dwParam1, DWORD dwParam2)
 {
     switch(wMsg) {
     case DRV_LOAD:		return 1;
-    case DRV_FREE:		return 1;
-    case DRV_OPEN:		return 1;	
-    case DRV_CLOSE:		return 1;
+    case DRV_FREE:		return 1; 
+    case DRV_OPEN:		return ANIM_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
+    case DRV_CLOSE:		return ANIM_drvClose(dwDevID);
     case DRV_ENABLE:		return 1;
     case DRV_DISABLE:		return 1;
     case DRV_QUERYCONFIGURE:	return 1;
-    case DRV_CONFIGURE:		MessageBoxA(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK); return 1;
+    case DRV_CONFIGURE:		MessageBoxA(0, "Sample MultiMedia Driver !", "Wine Driver", MB_OK); return 1;
     case DRV_INSTALL:		return DRVCNF_RESTART;
     case DRV_REMOVE:		return DRVCNF_RESTART;
-
+	
     case MCI_OPEN_DRIVER:	return ANIM_mciOpen(dwDevID, dwParam1, (LPMCI_OPEN_PARMSA)dwParam2); 
     case MCI_CLOSE_DRIVER:	return ANIM_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
     case MCI_GETDEVCAPS:	return ANIM_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
@@ -642,5 +690,4 @@
     return MCIERR_UNRECOGNIZED_COMMAND;
 }
 
-
 /*-----------------------------------------------------------------------*/
diff --git a/multimedia/mciavi.c b/multimedia/mciavi.c
index 0dd3bdd..b36fdee 100644
--- a/multimedia/mciavi.c
+++ b/multimedia/mciavi.c
@@ -15,11 +15,10 @@
 #include "digitalv.h"
 #include "options.h"
 
-DECLARE_DEBUG_CHANNEL(cdaudio)
 DECLARE_DEBUG_CHANNEL(mciavi)
-DECLARE_DEBUG_CHANNEL(mcimidi)
 
 typedef struct {
+    UINT		wDevID;
     int			nUseCount;          	/* Incremented for each shared open          */
     BOOL16  		fShareable;         	/* TRUE if first open was shareable 	     */
     WORD		wNotifyDeviceID;    	/* MCI device ID with a pending notification */
@@ -38,15 +37,64 @@
  *======================================================================*/
 
 /**************************************************************************
+ * 				AVI_drvGetDrv		[internal]	
+ */
+static WINE_MCIAVI*  AVI_drvGetDrv(UINT16 wDevID)
+{
+    int	i;
+
+    for (i = 0; i < MAX_MCIAVIDRV; i++) {
+	if (MCIAviDev[i].wDevID == wDevID) {
+	    return &MCIAviDev[i];
+	}
+    }
+    return 0;
+}
+
+/**************************************************************************
+ * 				AVI_drvOpen			[internal]	
+ */
+static	DWORD	AVI_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
+{
+    int	i;
+
+    for (i = 0; i < MAX_MCIAVIDRV; i++) {
+	if (MCIAviDev[i].wDevID == 0) {
+	    MCIAviDev[i].wDevID = modp->wDeviceID;
+	    modp->wCustomCommandTable = -1;
+	    modp->wType = MCI_DEVTYPE_CD_AUDIO;
+	    return modp->wDeviceID;
+	}
+    }
+    return 0;
+}
+
+/**************************************************************************
+ * 				MCIAVI_drvClose		[internal]	
+ */
+static	DWORD	AVI_drvClose(DWORD dwDevID)
+{
+    WINE_MCIAVI*  wma = AVI_drvGetDrv(dwDevID);
+
+    if (wma) {
+	wma->wDevID = 0;
+	return 1;
+    }
+    return 0;
+}
+
+/**************************************************************************
  * 				AVI_mciGetOpenDev		[internal]	
  */
 static WINE_MCIAVI*  AVI_mciGetOpenDev(UINT16 wDevID)
 {
-    if (wDevID >= MAX_MCIAVIDRV || MCIAviDev[wDevID].nUseCount == 0) {
+    WINE_MCIAVI*	wma = AVI_drvGetDrv(wDevID);
+    
+    if (wma == NULL || wma->nUseCount == 0) {
 	WARN(mciavi, "Invalid wDevID=%u\n", wDevID);
 	return 0;
     }
-    return &MCIAviDev[wDevID];
+    return wma;
 }
 
 static	DWORD	AVI_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
@@ -56,14 +104,12 @@
  */
 static	DWORD	AVI_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_DGV_OPEN_PARMSA lpParms)
 {
-    WINE_MCIAVI*	wma;
+    WINE_MCIAVI*	wma = AVI_drvGetDrv(wDevID);
     
     TRACE(mciavi, "(%04x, %08lX, %p) : semi-stub\n", wDevID, dwFlags, lpParms);
     
     if (lpParms == NULL) 		return MCIERR_NULL_PARAMETER_BLOCK;
-    if (wDevID > MAX_MCIAVIDRV)		return MCIERR_INVALID_DEVICE_ID;
-    
-    wma = &MCIAviDev[wDevID];
+    if (wma == NULL)			return MCIERR_INVALID_DEVICE_ID;
     
     if (wma->nUseCount > 0) {
 	/* The driver is already open on this channel */
@@ -78,7 +124,7 @@
 	wma->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
     }
     if (dwFlags & MCI_OPEN_ELEMENT) {
-	TRACE(cdaudio,"MCI_OPEN_ELEMENT !\n");
+	TRACE(mciavi,"MCI_OPEN_ELEMENT !\n");
 	/*		return MCIERR_NO_ELEMENT_ALLOWED; */
     }
     
@@ -130,7 +176,7 @@
     
     wma->wStatus = MCI_MODE_PLAY;
     if (lpParms && (dwFlags & MCI_NOTIFY)) {
-	TRACE(mcimidi, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
+	TRACE(mciavi, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
 	mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
 			  wma->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
     }
@@ -933,14 +979,14 @@
 /**************************************************************************
  * 				MCIAVI_DriverProc	[sample driver]
  */
-LONG MCIAVI_DriverProc(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
+LONG MCIAVI_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
 		       DWORD dwParam1, DWORD dwParam2)
 {
     switch (wMsg) {
     case DRV_LOAD:		return 1;
     case DRV_FREE:		return 1;
-    case DRV_OPEN:		return 1;
-    case DRV_CLOSE:		return 1;
+    case DRV_OPEN:		return AVI_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
+    case DRV_CLOSE:		return AVI_drvClose(dwDevID);
     case DRV_ENABLE:		return 1;
     case DRV_DISABLE:		return 1;
     case DRV_QUERYCONFIGURE:	return 1;
diff --git a/multimedia/mcicda.c b/multimedia/mcicda.c
index a588adf..a58cbb5 100644
--- a/multimedia/mcicda.c
+++ b/multimedia/mcicda.c
@@ -10,12 +10,13 @@
 #include "winuser.h"
 #include "driver.h"
 #include "multimedia.h"
-#include "debug.h"
 #include "cdrom.h"
+#include "debug.h"
 
 DEFAULT_DEBUG_CHANNEL(cdaudio)
 
 typedef struct {
+    UINT16		wDevID;
     int     		nUseCount;          /* Incremented for each shared open */
     BOOL16  		fShareable;         /* TRUE if first open was shareable */
     WORD    		wNotifyDeviceID;    /* MCI device ID with a pending notification */
@@ -32,16 +33,64 @@
 /*-----------------------------------------------------------------------*/
 
 /**************************************************************************
+ * 				CDAUDIO_drvGetDrv		[internal]	
+ */
+static WINE_MCICDAUDIO*  CDAUDIO_drvGetDrv(UINT16 wDevID)
+{
+    int	i;
+
+    for (i = 0; i < MAX_CDAUDIODRV; i++) {
+	if (CDADev[i].wDevID == wDevID) {
+	    return &CDADev[i];
+	}
+    }
+    return 0;
+}
+
+/**************************************************************************
+ * 				CDAUDIO_drvOpen			[internal]	
+ */
+static	DWORD	CDAUDIO_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
+{
+    int	i;
+
+    for (i = 0; i < MAX_CDAUDIODRV; i++) {
+	if (CDADev[i].wDevID == 0) {
+	    CDADev[i].wDevID = modp->wDeviceID;
+	    modp->wCustomCommandTable = -1;
+	    modp->wType = MCI_DEVTYPE_CD_AUDIO;
+	    return modp->wDeviceID;
+	}
+    }
+    return 0;
+}
+
+/**************************************************************************
+ * 				CDAUDIO_drvClose		[internal]	
+ */
+static	DWORD	CDAUDIO_drvClose(DWORD dwDevID)
+{
+    WINE_MCICDAUDIO*  wmcda = CDAUDIO_drvGetDrv(dwDevID);
+
+    if (wmcda) {
+	wmcda->wDevID = 0;
+	return 1;
+    }
+    return 0;
+}
+
+/**************************************************************************
  * 				CDAUDIO_mciGetOpenDrv		[internal]	
  */
 static WINE_MCICDAUDIO*  CDAUDIO_mciGetOpenDrv(UINT16 wDevID)
 {
-    if (wDevID >= MAX_CDAUDIODRV || CDADev[wDevID].nUseCount == 0 || 
-	CDADev[wDevID].wcda.unixdev <= 0) {
+    WINE_MCICDAUDIO*	wmcda = CDAUDIO_drvGetDrv(wDevID);
+    
+    if (wmcda == NULL || wmcda->nUseCount == 0 || wmcda->wcda.unixdev <= 0) {
 	WARN(cdaudio, "Invalid wDevID=%u\n", wDevID);
 	return 0;
     }
-    return &CDADev[wDevID];
+    return wmcda;
 }
 
 /**************************************************************************
@@ -173,18 +222,16 @@
 static DWORD CDAUDIO_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_OPEN_PARMSA lpOpenParms)
 {
     DWORD		dwDeviceID;
-    WINE_MCICDAUDIO* 	wmcda;
+    WINE_MCICDAUDIO* 	wmcda = CDAUDIO_drvGetDrv(wDevID);
     MCI_SEEK_PARMS 	seekParms;
 
     TRACE(cdaudio,"(%04X, %08lX, %p);\n", wDevID, dwFlags, lpOpenParms);
     
     if (lpOpenParms == NULL) 		return MCIERR_NULL_PARAMETER_BLOCK;
-    if (wDevID > MAX_CDAUDIODRV)	return MCIERR_INVALID_DEVICE_ID;
+    if (wmcda == NULL)			return MCIERR_INVALID_DEVICE_ID;
 
     dwDeviceID = lpOpenParms->wDeviceID;
 
-    wmcda = &CDADev[wDevID];
-
     if (wmcda->nUseCount > 0) {
 	/* The driver is already open on this channel */
 	/* If the driver was opened shareable before and this open specifies */
@@ -671,18 +718,18 @@
 /**************************************************************************
  * 			MCICDAUDIO_DriverProc			[sample driver]
  */
-LONG MCICDAUDIO_DriverProc(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
+LONG MCICDAUDIO_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
 			   DWORD dwParam1, DWORD dwParam2)
 {
     switch(wMsg) {
     case DRV_LOAD:		return 1;
     case DRV_FREE:		return 1;
-    case DRV_OPEN:		return 1;
-    case DRV_CLOSE:		return 1;
+    case DRV_OPEN:		return CDAUDIO_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
+    case DRV_CLOSE:		return CDAUDIO_drvClose(dwDevID);
     case DRV_ENABLE:		return 1;	
     case DRV_DISABLE:		return 1;
     case DRV_QUERYCONFIGURE:	return 1;
-    case DRV_CONFIGURE:		MessageBoxA(0, "Sample Multimedia Linux Driver !", "MMLinux Driver", MB_OK); return 1;
+    case DRV_CONFIGURE:		MessageBoxA(0, "Sample Multimedia Driver !", "Wine Driver", MB_OK); return 1;
     case DRV_INSTALL:		return DRVCNF_RESTART;
     case DRV_REMOVE:		return DRVCNF_RESTART;
 	
diff --git a/multimedia/mcimidi.c b/multimedia/mcimidi.c
index 3816fc6..87d402c 100644
--- a/multimedia/mcimidi.c
+++ b/multimedia/mcimidi.c
@@ -22,13 +22,11 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include "winuser.h"
-#include "ldt.h"
 #include "multimedia.h"
 #include "user.h"
 #include "driver.h"
-#include "xmalloc.h"
-#include "debug.h"
 #include "heap.h"
+#include "debug.h"
 
 DECLARE_DEBUG_CHANNEL(mcimidi)
 DECLARE_DEBUG_CHANNEL(midi)
@@ -47,6 +45,8 @@
 } MCI_MIDITRACK;
 
 typedef struct {
+    UINT16		wDevID;
+    UINT16		wMidiID;
     int			nUseCount;          	/* Incremented for each shared open          */
     WORD		wNotifyDeviceID;    	/* MCI device ID with a pending notification */
     HANDLE16 		hCallback;         	/* Callback handle for pending notification  */
@@ -75,15 +75,64 @@
 
 #ifdef SNDCTL_MIDI_INFO
 /**************************************************************************
+ * 				MIDI_drvGetDrv		[internal]	
+ */
+static WINE_MCIMIDI*  MIDI_drvGetDrv(UINT16 wDevID)
+{
+    int	i;
+
+    for (i = 0; i < MAX_MCIMIDIDRV; i++) {
+	if (MCIMidiDev[i].wDevID == wDevID) {
+	    return &MCIMidiDev[i];
+	}
+    }
+    return 0;
+}
+
+/**************************************************************************
+ * 				MIDI_drvOpen			[internal]	
+ */
+static	DWORD	MIDI_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
+{
+    int	i;
+
+    for (i = 0; i < MAX_MCIMIDIDRV; i++) {
+	if (MCIMidiDev[i].wDevID == 0) {
+	    MCIMidiDev[i].wDevID = modp->wDeviceID;
+	    modp->wCustomCommandTable = -1;
+	    modp->wType = MCI_DEVTYPE_CD_AUDIO;
+	    return modp->wDeviceID;
+	}
+    }
+    return 0;
+}
+
+/**************************************************************************
+ * 				MCIMIDI_drvClose		[internal]	
+ */
+static	DWORD	MIDI_drvClose(DWORD dwDevID)
+{
+    WINE_MCIMIDI*  wmm = MIDI_drvGetDrv(dwDevID);
+
+    if (wmm) {
+	wmm->wDevID = 0;
+	return 1;
+    }
+    return 0;
+}
+
+/**************************************************************************
  * 				MIDI_mciGetOpenDev		[internal]	
  */
 static WINE_MCIMIDI*  MIDI_mciGetOpenDev(UINT16 wDevID)
 {
-    if (wDevID >= MAX_MCIMIDIDRV || MCIMidiDev[wDevID].nUseCount == 0) {
+    WINE_MCIMIDI*	wmm = MIDI_drvGetDrv(wDevID);
+    
+    if (wmm == NULL || wmm->nUseCount == 0) {
 	WARN(mcimidi, "Invalid wDevID=%u\n", wDevID);
 	return 0;
     }
-    return &MCIMidiDev[wDevID];
+    return wmm;
 }
 
 /**************************************************************************
@@ -96,7 +145,7 @@
     if (lpbyt == NULL || 
 	mmioRead(wmm->hFile, (HPSTR)lpbyt, (long)sizeof(BYTE)) != (long)sizeof(BYTE)) {
 	WARN(mcimidi, "Error reading wmm=%p\n", wmm);
-	ret = MCIERR_INTERNAL;
+	ret = MCIERR_INVALID_FILE;
     }
     
     return ret;
@@ -108,7 +157,7 @@
 static DWORD MIDI_mciReadWord(WINE_MCIMIDI* wmm, LPWORD lpw)
 {
     BYTE	hibyte, lobyte;
-    DWORD	ret = MCIERR_INTERNAL;
+    DWORD	ret = MCIERR_INVALID_FILE;
     
     if (lpw != NULL && 
 	MIDI_mciReadByte(wmm, &hibyte) == 0 && 
@@ -125,7 +174,7 @@
 static DWORD MIDI_mciReadLong(WINE_MCIMIDI* wmm, LPDWORD lpdw)
 {
     WORD	hiword, loword;
-    DWORD	ret = MCIERR_INTERNAL;
+    DWORD	ret = MCIERR_INVALID_FILE;
     
     if (lpdw != NULL &&
 	MIDI_mciReadWord(wmm, &hiword) == 0 &&
@@ -146,7 +195,7 @@
     WORD	ret = 0;
     
     if (lpdw == NULL) {
-	ret = MCIERR_INTERNAL;
+	ret = MCIERR_INVALID_FILE;
     } else {
 	do {
 	    if (MIDI_mciReadByte(wmm, &byte) != 0) {
@@ -176,7 +225,7 @@
     
     if (mmioSeek(wmm->hFile, mmt->dwIndex, SEEK_SET) != mmt->dwIndex) {
 	WARN(mcimidi, "Can't seek at %08lX \n", mmt->dwIndex);
-	return MCIERR_INTERNAL;
+	return MCIERR_INVALID_FILE;
     }
     evtLength = MIDI_mciReadVaryLen(wmm, &evtPulse) + 1;	/* > 0 */
     MIDI_mciReadByte(wmm, &b1);
@@ -244,16 +293,16 @@
     
     if (mmioRead(wmm->hFile, (HPSTR)&fourcc, (long)sizeof(FOURCC)) != 
 	(long)sizeof(FOURCC)) {
-	return MCIERR_INTERNAL;
+	return MCIERR_INVALID_FILE;
     }
     
     if (fourcc != mmioFOURCC('M', 'T', 'r', 'k')) {
 	WARN(mcimidi, "Can't synchronize on 'MTrk' !\n");
-	return MCIERR_INTERNAL;
+	return MCIERR_INVALID_FILE;
     }
     
     if (MIDI_mciReadLong(wmm, &toberead) != 0) {
-	return MCIERR_INTERNAL;
+	return MCIERR_INVALID_FILE;
     }
     mmt->dwFirst = mmioSeek(wmm->hFile, 0, SEEK_CUR); /* >= 0 */
     mmt->dwLast = mmt->dwFirst + toberead;
@@ -298,24 +347,24 @@
     
     if (mmioSeek(wmm->hFile, dwOffset, SEEK_SET) != dwOffset) {
 	WARN(mcimidi, "Can't seek at %08lX begin of 'MThd' \n", dwOffset);
-	return MCIERR_INTERNAL;
+	return MCIERR_INVALID_FILE;
     }
     if (mmioRead(wmm->hFile, (HPSTR)&fourcc,
 		   (long) sizeof(FOURCC)) != (long) sizeof(FOURCC))
-	return MCIERR_INTERNAL;
+	return MCIERR_INVALID_FILE;
     
     if (fourcc != mmioFOURCC('M', 'T', 'h', 'd')) {
 	WARN(mcimidi, "Can't synchronize on 'MThd' !\n");
-	return MCIERR_INTERNAL;
+	return MCIERR_INVALID_FILE;
     }
     
     if (MIDI_mciReadLong(wmm, &toberead) != 0 || toberead < 3 * sizeof(WORD))
-	return MCIERR_INTERNAL;
+	return MCIERR_INVALID_FILE;
     
     if (MIDI_mciReadWord(wmm, &wmm->wFormat) != 0 ||
 	MIDI_mciReadWord(wmm, &wmm->nTracks) != 0 ||
 	MIDI_mciReadWord(wmm, &wmm->nDivision) != 0) {
-	return MCIERR_INTERNAL;
+	return MCIERR_INVALID_FILE;
     }
     
     TRACE(mcimidi, "toberead=0x%08lX, wFormat=0x%04X nTracks=0x%04X nDivision=0x%04X\n",
@@ -341,7 +390,7 @@
 	case 0xE2:	wmm->dwMciTimeFormat = MCI_FORMAT_SMPTE_30;	break;	/* -30 */
 	default:
 	    WARN(mcimidi, "Unsupported number of frames %d\n", -(char)HIBYTE(wmm->nDivision));
-	    return MCIERR_INTERNAL;
+	    return MCIERR_INVALID_FILE;
 	}
 	switch (LOBYTE(wmm->nDivision)) {
 	case 4:	/* MIDI Time Code */
@@ -351,12 +400,11 @@
 	case 100:
 	default:
 	    WARN(mcimidi, "Unsupported number of sub-frames %d\n", LOBYTE(wmm->nDivision));
-	    return MCIERR_INTERNAL;
+	    return MCIERR_INVALID_FILE;
 	}
-	return MCIERR_INTERNAL;
     } else if (wmm->nDivision == 0) {
 	WARN(mcimidi, "Number of division is 0, can't support that !!\n");
-	return MCIERR_INTERNAL;
+	return MCIERR_INVALID_FILE;
     } else {
 	wmm->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
     }
@@ -374,7 +422,7 @@
     default:
 	WARN(mcimidi, "Handling MIDI files which format = %d is not (yet) supported\n"
 	     "Please report with MIDI file !\n", wmm->wFormat);
-	return MCIERR_INTERNAL;
+	return MCIERR_INVALID_FILE;
     }
     
     if (wmm->nTracks & 0x8000) {
@@ -383,7 +431,9 @@
 	wmm->nTracks = 0x7FFF;
     }
     
-    wmm->tracks = xmalloc(sizeof(MCI_MIDITRACK) * wmm->nTracks);
+    if ((wmm->tracks = malloc(sizeof(MCI_MIDITRACK) * wmm->nTracks)) == NULL) {
+	return MCIERR_OUT_OF_MEMORY;
+    }
     
     toberead -= 3 * sizeof(WORD); 
     if (toberead > 0) {
@@ -395,7 +445,7 @@
 	wmm->tracks[nt].wTrackNr = nt;
 	if (MIDI_mciReadMTrk(wmm, &wmm->tracks[nt]) != 0) {
 	    WARN(mcimidi, "Can't read 'MTrk' header \n");
-	    return MCIERR_INTERNAL;
+	    return MCIERR_INVALID_FILE;
 	}
     }
     
@@ -547,20 +597,15 @@
     MIDIOPENDESC 	midiOpenDesc;
     DWORD		dwRet = 0;
     DWORD		dwDeviceID;
-    WINE_MCIMIDI*	wmm;
+    WINE_MCIMIDI*	wmm = MIDI_drvGetDrv(wDevID);
     
     TRACE(mcimidi, "(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
     
     if (lpParms == NULL) 	return MCIERR_NULL_PARAMETER_BLOCK;
-    if (wDevID >= MAX_MCIMIDIDRV) {
-	WARN(mcimidi, "Invalid wDevID=%u\n", wDevID);
-	return MCIERR_INVALID_DEVICE_ID;
-    }	
+    if (wmm == NULL)		return MCIERR_INVALID_DEVICE_ID;
     if (dwFlags & MCI_OPEN_SHAREABLE)
 	return MCIERR_HARDWARE;
 
-    wmm = &MCIMidiDev[wDevID];
-    
     if (wmm->nUseCount > 0) {
 	/* The driver is already opened on this channel
 	 * MIDI sequencer cannot be shared
@@ -570,6 +615,7 @@
     wmm->nUseCount++;
     
     wmm->hFile = 0;
+    wmm->wMidiID = 0;
     dwDeviceID = lpParms->wDeviceID;
     
     TRACE(mcimidi, "wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID, dwDeviceID);
@@ -645,8 +691,8 @@
 	wmm->dwStatus = MCI_MODE_STOP;
 	wmm->hMidiHdr = USER_HEAP_ALLOC(sizeof(MIDIHDR16));
 	
-	dwRet = modMessage(wDevID, MODM_OPEN, 0, (DWORD)&midiOpenDesc, CALLBACK_NULL);
-	/*	dwRet = midMessage(wDevID, MIDM_OPEN, 0, (DWORD)&midiOpenDesc, CALLBACK_NULL);*/
+	dwRet = modMessage(wmm->wMidiID, MODM_OPEN, 0, (DWORD)&midiOpenDesc, CALLBACK_NULL);
+	/*	dwRet = midMessage(wmm->wMidiID, MIDM_OPEN, 0, (DWORD)&midiOpenDesc, CALLBACK_NULL);*/
     }
     return dwRet;
 }
@@ -699,10 +745,10 @@
 	}
 	USER_HEAP_FREE(wmm->hMidiHdr);
 	free(wmm->tracks);
-	dwRet = modMessage(wDevID, MODM_CLOSE, 0, 0L, 0L);
+	dwRet = modMessage(wmm->wMidiID, MODM_CLOSE, 0, 0L, 0L);
 	if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
 	/*
-	  dwRet = midMessage(wDevID, MIDM_CLOSE, 0, 0L, 0L);
+	  dwRet = midMessage(wmm->wMidiID, MIDM_CLOSE, 0, 0L, 0L);
 	  if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
 	*/
     } else {
@@ -974,7 +1020,7 @@
 	    break;
 	default:
 	    if (doPlay) {
-		dwRet = modMessage(wDevID, MODM_DATA, 0, mmt->dwEventData, 0);
+		dwRet = modMessage(wmm->wMidiID, MODM_DATA, 0, mmt->dwEventData, 0);
 	    } else {
 		switch (LOBYTE(LOWORD(mmt->dwEventData)) & 0xF0) {
 		case MIDI_NOTEON:
@@ -982,7 +1028,7 @@
 		    dwRet = 0;	
 		    break;
 		default:
-		    dwRet = modMessage(wDevID, MODM_DATA, 0, mmt->dwEventData, 0);
+		    dwRet = modMessage(wmm->wMidiID, MODM_DATA, 0, mmt->dwEventData, 0);
 		}
 	    }
 	}
@@ -1006,7 +1052,7 @@
     {
 	unsigned chn;
 	for (chn = 0; chn < 16; chn++)
-	    modMessage(wDevID, MODM_DATA, 0, 0x78B0 | chn, 0);
+	    modMessage(wmm->wMidiID, MODM_DATA, 0, 0x78B0 | chn, 0);
     }
     
     wmm->dwStatus = MCI_MODE_STOP;
@@ -1051,24 +1097,26 @@
 	TRACE(mcimidi, "MCI_TO=%d \n", end);
     }
     lpMidiHdr = USER_HEAP_LIN_ADDR(wmm->hMidiHdr);
-    lpMidiHdr->lpData = (LPSTR) xmalloc(1200);
+    lpMidiHdr->lpData = (LPSTR) malloc(1200);
+    if (!lpMidiHdr)
+	return MCIERR_OUT_OF_MEMORY;
     lpMidiHdr->dwBufferLength = 1024;
     lpMidiHdr->dwUser = 0L;
     lpMidiHdr->dwFlags = 0L;
-    dwRet = midMessage(wDevID, MIDM_PREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR16));
+    dwRet = midMessage(wmm->wMidiID, MIDM_PREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR16));
     TRACE(mcimidi, "After MIDM_PREPARE \n");
     wmm->dwStatus = MCI_MODE_RECORD;
     while (wmm->dwStatus != MCI_MODE_STOP) {
 	TRACE(mcimidi, "wmm->dwStatus=%p %d\n",
 	      &wmm->dwStatus, wmm->dwStatus);
 	lpMidiHdr->dwBytesRecorded = 0;
-	dwRet = midMessage(wDevID, MIDM_START, 0, 0L, 0L);
+	dwRet = midMessage(wmm->wMidiID, MIDM_START, 0, 0L, 0L);
 	TRACE(mcimidi, "After MIDM_START lpMidiHdr=%p dwBytesRecorded=%lu\n",
 	      lpMidiHdr, lpMidiHdr->dwBytesRecorded);
 	if (lpMidiHdr->dwBytesRecorded == 0) break;
     }
     TRACE(mcimidi, "Before MIDM_UNPREPARE \n");
-    dwRet = midMessage(wDevID, MIDM_UNPREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR16));
+    dwRet = midMessage(wmm->wMidiID, MIDM_UNPREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR16));
     TRACE(mcimidi, "After MIDM_UNPREPARE \n");
     if (lpMidiHdr->lpData != NULL) {
 	free(lpMidiHdr->lpData);
@@ -1099,7 +1147,7 @@
 	/* see note in MIDI_mciPlay */
 	unsigned chn;
 	for (chn = 0; chn < 16; chn++)
-	    modMessage(wDevID, MODM_DATA, 0, 0x78B0 | chn, 0);
+	    modMessage(wmm->wMidiID, MODM_DATA, 0, 0x78B0 | chn, 0);
 	wmm->dwStatus = MCI_MODE_PAUSE;
     } 
     if (lpParms && (dwFlags & MCI_NOTIFY)) {
@@ -1475,18 +1523,18 @@
 /**************************************************************************
  * 				MCIMIDI_DriverProc	     [sample driver]
  */
-LONG MCIMIDI_DriverProc(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
+LONG MCIMIDI_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
 			DWORD dwParam1, DWORD dwParam2)
 {
     switch (wMsg) {
     case DRV_LOAD:		return 1;
     case DRV_FREE:		return 1;
-    case DRV_OPEN:		return 1;
-    case DRV_CLOSE:		return 1;
+    case DRV_OPEN:		return MIDI_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
+    case DRV_CLOSE:		return MIDI_drvClose(dwDevID);
     case DRV_ENABLE:		return 1;
     case DRV_DISABLE:		return 1;
     case DRV_QUERYCONFIGURE:	return 1;
-    case DRV_CONFIGURE:		MessageBoxA(0, "Sample Midi Linux Driver !", "MMLinux Driver", MB_OK); return 1;
+    case DRV_CONFIGURE:		MessageBoxA(0, "Sample Midi Driver !", "OSS Driver", MB_OK); return 1;
     case DRV_INSTALL:		return DRVCNF_RESTART;
     case DRV_REMOVE:		return DRVCNF_RESTART;
 #ifdef SNDCTL_MIDI_INFO
diff --git a/multimedia/mcistring.c b/multimedia/mcistring.c
index b471e3d..d0c296e 100644
--- a/multimedia/mcistring.c
+++ b/multimedia/mcistring.c
@@ -275,7 +275,7 @@
 	pU->openParams.lpstrElementName = strdup(s);
 	dwFlags |= MCI_OPEN_ELEMENT;
     }
-    uDevTyp = MCI_GetDevType(dev);
+    uDevTyp = MCI_GetDevTypeFromString(dev);
     if (uDevTyp == 0) {
 	free(pU->openParams.lpstrElementName);
 	free(pU);
diff --git a/multimedia/mciwave.c b/multimedia/mciwave.c
index 6b6ec27..1b5d2d6 100644
--- a/multimedia/mciwave.c
+++ b/multimedia/mciwave.c
@@ -32,6 +32,8 @@
 #define MAX_MCIWAVEDRV 	(1)
 
 typedef struct {
+    UINT16			wDevID;
+    UINT16			wWavID;
     int				nUseCount;	/* Incremented for each shared open */
     BOOL16			fShareable;	/* TRUE if first open was shareable */
     WORD			wNotifyDeviceID;/* MCI device ID with a pending notification */
@@ -56,15 +58,64 @@
  *======================================================================*/
 
 /**************************************************************************
+ * 				MCIWAVE_drvGetDrv		[internal]	
+ */
+static WINE_MCIWAVE*  WAVE_drvGetDrv(UINT16 wDevID)
+{
+    int	i;
+
+    for (i = 0; i < MAX_MCIWAVEDRV; i++) {
+	if (MCIWaveDev[i].wDevID == wDevID) {
+	    return &MCIWaveDev[i];
+	}
+    }
+    return 0;
+}
+
+/**************************************************************************
+ * 				MCIWAVE_drvOpen			[internal]	
+ */
+static	DWORD	WAVE_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
+{
+    int	i;
+
+    for (i = 0; i < MAX_MCIWAVEDRV; i++) {
+	if (MCIWaveDev[i].wDevID == 0) {
+	    MCIWaveDev[i].wDevID = modp->wDeviceID;
+	    modp->wCustomCommandTable = -1;
+	    modp->wType = MCI_DEVTYPE_WAVEFORM_AUDIO;
+	    return modp->wDeviceID;
+	}
+    }
+    return 0;
+}
+
+/**************************************************************************
+ * 				MCIWAVE_drvClose		[internal]	
+ */
+static	DWORD	WAVE_drvClose(DWORD dwDevID)
+{
+    WINE_MCIWAVE*  wmcda = WAVE_drvGetDrv(dwDevID);
+
+    if (wmcda) {
+	wmcda->wDevID = 0;
+	return 1;
+    }
+    return 0;
+}
+
+/**************************************************************************
  * 				WAVE_mciGetOpenDev		[internal]	
  */
 static WINE_MCIWAVE*  WAVE_mciGetOpenDev(UINT16 wDevID)
 {
-    if (wDevID >= MAX_MCIWAVEDRV || MCIWaveDev[wDevID].nUseCount == 0) {
+    WINE_MCIWAVE*	wmw = WAVE_drvGetDrv(wDevID);
+    
+    if (wmw == NULL || wmw->nUseCount == 0) {
 	WARN(mciwave, "Invalid wDevID=%u\n", wDevID);
 	return 0;
     }
-    return &MCIWaveDev[wDevID];
+    return wmw;
 }
 
 static	DWORD 	WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val)
@@ -147,20 +198,15 @@
 {
     DWORD		dwRet = 0;
     DWORD		dwDeviceID;
-    WINE_MCIWAVE*	wmw;
+    WINE_MCIWAVE*	wmw = WAVE_drvGetDrv(wDevID);
     
     TRACE(mciwave, "(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
-    if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
-    
-    if (wDevID >= MAX_MCIWAVEDRV) {
-	WARN(mciwave, "Invalid wDevID=%u\n", wDevID);
-	return MCIERR_INVALID_DEVICE_ID;
-    }
+    if (lpOpenParms == NULL)	return MCIERR_NULL_PARAMETER_BLOCK;
+    if (wmw == NULL) 		return MCIERR_INVALID_DEVICE_ID;
+
     if (dwFlags & MCI_OPEN_SHAREABLE)
 	return MCIERR_HARDWARE;
     
-    wmw = &MCIWaveDev[wDevID];
-    
     if (wmw->nUseCount > 0) {
 	/* The driver is already opened on this channel
 	 * Wave driver cannot be shared
@@ -172,7 +218,8 @@
     dwDeviceID = lpOpenParms->wDeviceID;
     
     wmw->fInput = FALSE;
-    
+    wmw->wWavID = 0;
+
     TRACE(mciwave, "wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID, dwDeviceID);
     
     if (dwFlags & MCI_OPEN_ELEMENT) {
@@ -272,14 +319,14 @@
     dwRet = MMSYSERR_NOERROR;  /* assume success */
     
     if ((dwParam & MCI_WAVE_INPUT) && !wmw->fInput) {
-	dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
+	dwRet = wodMessage(wmw->wWavID, WODM_CLOSE, 0, 0L, 0L);
 	if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
-	dwRet = widMessage(wDevID, WIDM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
+	dwRet = widMessage(wmw->wWavID, WIDM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
 	wmw->fInput = TRUE;
     } else if (wmw->fInput) {
-	dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
+	dwRet = widMessage(wmw->wWavID, WIDM_CLOSE, 0, 0L, 0L);
 	if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
-	dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
+	dwRet = wodMessage(wmw->wWavID, WODM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
 	wmw->fInput = FALSE;
     }
     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
@@ -303,9 +350,9 @@
     TRACE(mciwave, "wmw->dwStatus=%d\n", wmw->dwStatus);
     
     if (wmw->fInput)
-	dwRet = widMessage(wDevID, WIDM_STOP, 0, dwFlags, (DWORD)lpParms);
+	dwRet = widMessage(wmw->wWavID, WIDM_STOP, 0, dwFlags, (DWORD)lpParms);
     else
-	dwRet = wodMessage(wDevID, WODM_STOP, 0, dwFlags, (DWORD)lpParms);
+	dwRet = wodMessage(wmw->wWavID, WODM_STOP, 0, dwFlags, (DWORD)lpParms);
     
     if (dwFlags & MCI_NOTIFY) {
 	TRACE(mciwave, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
@@ -340,8 +387,8 @@
 	    mmioClose(wmw->hFile, 0);
 	    wmw->hFile = 0;
 	}
-	mmRet = (wmw->fInput) ? widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L) :
-	    wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
+	mmRet = (wmw->fInput) ? widMessage(wmw->wWavID, WIDM_CLOSE, 0, 0L, 0L) :
+	    wodMessage(wmw->wWavID, WODM_CLOSE, 0, 0L, 0L);
 	
 	if (mmRet != MMSYSERR_NOERROR) dwRet = MCIERR_INTERNAL;
     }
@@ -402,7 +449,8 @@
     /* 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)&wmw->waveDesc, CALLBACK_NULL);
+    /* FIXME: how to choose between several output channels ? here 0 is forced */
+    dwRet = wodMessage(0, WODM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
     if (dwRet != 0) {
 	TRACE(mciwave, "Can't open low level audio device %ld\n", dwRet);
 	return MCIERR_DEVICE_OPEN;
@@ -416,6 +464,8 @@
     wmw->dwStatus = MCI_MODE_PLAY;
     
     /* FIXME: this doesn't work if wmw->dwPosition != 0 */
+    /* FIXME: use several WaveHdr for smoother playback */
+    /* FIXME: use only regular MMSYS functions, not calling directly the driver */
     while (wmw->dwStatus != MCI_MODE_STOP) {
 	wmw->WaveHdr.dwUser = 0L;
 	wmw->WaveHdr.dwFlags = 0L;
@@ -424,12 +474,14 @@
 	TRACE(mciwave, "mmioRead bufsize=%ld count=%ld\n", bufsize, count);
 	if (count < 1) 
 	    break;
-	dwRet = wodMessage(wDevID, WODM_PREPARE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
+	dwRet = wodMessage(wmw->wWavID, WODM_PREPARE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
 	wmw->WaveHdr.dwBufferLength = count;
 	wmw->WaveHdr.dwBytesRecorded = 0;
+	/* FIXME */
+	wmw->WaveHdr.reserved = (DWORD)&wmw->WaveHdr;
 	TRACE(mciwave, "before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
 	      &wmw->WaveHdr, wmw->WaveHdr.dwBufferLength, wmw->WaveHdr.dwBytesRecorded);
-	dwRet = wodMessage(wDevID, WODM_WRITE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
+	dwRet = wodMessage(wmw->wWavID, WODM_WRITE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
 	/* FIXME: should use callback mechanisms from audio driver */
 #if 1
 	while (!(wmw->WaveHdr.dwFlags & WHDR_DONE))
@@ -437,7 +489,7 @@
 #endif
 	wmw->dwPosition += count;
 	TRACE(mciwave, "after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
-	dwRet = wodMessage(wDevID, WODM_UNPREPARE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
+	dwRet = wodMessage(wmw->wWavID, WODM_UNPREPARE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
     }
     
     if (wmw->WaveHdr.lpData != NULL) {
@@ -446,8 +498,8 @@
 	wmw->WaveHdr.lpData = NULL;
     }
 
-    wodMessage(wDevID, WODM_STOP,  0, 0L, 0L);
-    wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
+    wodMessage(wmw->wWavID, WODM_STOP,  0, 0L, 0L);
+    wodMessage(wmw->wWavID, WODM_CLOSE, 0, 0L, 0L);
 
     wmw->dwStatus = MCI_MODE_STOP;
     if (lpParms && (dwFlags & MCI_NOTIFY)) {
@@ -502,17 +554,17 @@
     lpWaveHdr->dwUser = 0L;
     lpWaveHdr->dwFlags = 0L;
     lpWaveHdr->dwLoops = 0L;
-    dwRet = widMessage(wDevID,WIDM_PREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
+    dwRet = widMessage(wmw->wWavID,WIDM_PREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
     TRACE(mciwave, "after WIDM_PREPARE \n");
     while (TRUE) {
 	lpWaveHdr->dwBytesRecorded = 0;
-	dwRet = widMessage(wDevID, WIDM_START, 0, 0L, 0L);
+	dwRet = widMessage(wmw->wWavID, WIDM_START, 0, 0L, 0L);
 	TRACE(mciwave, "after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
 	      lpWaveHdr, lpWaveHdr->dwBytesRecorded);
 	if (lpWaveHdr->dwBytesRecorded == 0) break;
     }
     TRACE(mciwave, "before WIDM_UNPREPARE \n");
-    dwRet = widMessage(wDevID,WIDM_UNPREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
+    dwRet = widMessage(wmw->wWavID,WIDM_UNPREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
     TRACE(mciwave, "after WIDM_UNPREPARE \n");
     if (lpWaveHdr->lpData != NULL) {
 	GlobalUnlock16(hData);
@@ -544,8 +596,8 @@
 	wmw->dwStatus = MCI_MODE_PAUSE;
     } 
     
-    if (wmw->fInput)	dwRet = widMessage(wDevID, WIDM_PAUSE, 0, dwFlags, (DWORD)lpParms);
-    else		dwRet = wodMessage(wDevID, WODM_PAUSE, 0, dwFlags, (DWORD)lpParms);
+    if (wmw->fInput)	dwRet = widMessage(wmw->wWavID, WIDM_PAUSE, 0, dwFlags, (DWORD)lpParms);
+    else		dwRet = wodMessage(wmw->wWavID, WODM_PAUSE, 0, dwFlags, (DWORD)lpParms);
     
     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
 }
@@ -568,8 +620,8 @@
     } 
     
 #if 0
-    if (wmw->fInput)	dwRet = widMessage(wDevID, WIDM_PLAY, 0, dwFlags, (DWORD)lpParms);
-    else		dwRet = wodMessage(wDevID, WODM_PLAY, 0, dwFlags, (DWORD)lpParms);
+    if (wmw->fInput)	dwRet = widMessage(wmw->wWavID, WIDM_PLAY, 0, dwFlags, (DWORD)lpParms);
+    else		dwRet = wodMessage(wmw->wWavID, WODM_PLAY, 0, dwFlags, (DWORD)lpParms);
     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
 #else
     return dwRet;
@@ -906,7 +958,7 @@
 /**************************************************************************
  * 				MCIWAVE_DriverProc		[sample driver]
  */
-LONG MCIWAVE_DriverProc(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
+LONG MCIWAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
 			DWORD dwParam1, DWORD dwParam2)
 {
     TRACE(mciwave, "(%08lX, %04X, %08lX, %08lX, %08lX)\n", 
@@ -915,12 +967,12 @@
     switch(wMsg) {
     case DRV_LOAD:		return 1;
     case DRV_FREE:		return 1;
-    case DRV_OPEN:		return 1;
-    case DRV_CLOSE:		return 1;
+    case DRV_OPEN:		return WAVE_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
+    case DRV_CLOSE:		return WAVE_drvClose(dwDevID);
     case DRV_ENABLE:		return 1;
     case DRV_DISABLE:		return 1;
     case DRV_QUERYCONFIGURE:	return 1;
-    case DRV_CONFIGURE:		MessageBoxA(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK);	return 1;
+    case DRV_CONFIGURE:		MessageBoxA(0, "Sample MultiMedia Driver !", "OSS Driver", MB_OK);	return 1;
     case DRV_INSTALL:		return DRVCNF_RESTART;
     case DRV_REMOVE:		return DRVCNF_RESTART;
     case MCI_OPEN_DRIVER:	return WAVE_mciOpen      (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMSA)  dwParam2);
diff --git a/multimedia/mmsystem.c b/multimedia/mmsystem.c
index ba42274..6ebbd2a 100644
--- a/multimedia/mmsystem.c
+++ b/multimedia/mmsystem.c
@@ -8,7 +8,9 @@
 
 /* 
  * Eric POUECH : 
- * 98/9	added support for Win32 MCI
+ * 	98/9	added Win32 MCI support
+ *  	99/4	added mmTask and mmThread functions support
+ *		added midiStream support
  */
 
 /* FIXME: I think there are some segmented vs. linear pointer weirdnesses 
@@ -223,7 +225,9 @@
 					if (count < 1) break;
 					left -= count;
 					waveHdr.dwBufferLength = count;
-				/*	waveHdr.dwBytesRecorded = count; */
+					/* FIXME */
+					waveHdr.reserved = (DWORD)&waveHdr;
+				        /* waveHdr.dwBytesRecorded = count; */
 					/* FIXME: doesn't expect async ops */ 
 					wodMessage(0, WODM_WRITE, 0, (DWORD)&waveHdr, sizeof(WAVEHDR));
 				    }
@@ -434,34 +438,53 @@
 
     switch (uFlags & DCB_TYPEMASK) {
     case DCB_NULL:
-	TRACE(mmsys, "CALLBACK_NULL !\n");
+	TRACE(mmsys, "Null !\n");
 	break;
     case DCB_WINDOW:
-	TRACE(mmsys, "CALLBACK_WINDOW = %04lX handle = %04X!\n",
-	      dwCallBack, hDev);
+	TRACE(mmsys, "Window(%04lX) handle=%04X!\n", dwCallBack, hDev);
 	if (!IsWindow(dwCallBack) || USER_HEAP_LIN_ADDR(hDev) == NULL)
 	    return FALSE;
 	Callout.PostMessageA((HWND16)dwCallBack, wMsg, hDev, dwParam1);
 	break;
-    case DCB_TASK:
-	TRACE(mmsys, "CALLBACK_TASK !\n");
+    case DCB_TASK: /* aka DCB_THREAD */
+	TRACE(mmsys, "Task(%04lx) !\n", dwCallBack);
 	Callout.PostThreadMessageA(dwCallBack, wMsg, hDev, dwParam1);
 	break;
     case DCB_FUNCTION:
-	TRACE(mmsys, "CALLBACK_FUNCTION !\n");
+	TRACE(mmsys, "Function (16bit) !\n");
 	Callbacks->CallDriverCallback((FARPROC16)dwCallBack, hDev, wMsg, dwUser,
 				       dwParam1, dwParam2);
 	break;
-    case DCB_EVENT:
-	TRACE(mmsys, "CALLBACK_EVENT !\n");
-	SetEvent((HANDLE)dwCallBack);
-	break;
-    case DCB_FUNC32:
-	TRACE(mmsys, "CALLBACK_FUNCTION 32bit !\n");
+    case DCB_FUNC32: /* This is a Wine only value - AKAIF not used yet by MS */
+	TRACE(mmsys, "Function (32bit) !\n");
 	((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
 	break;
+    case DCB_EVENT:
+	TRACE(mmsys, "Event(%08lx) !\n", dwCallBack);
+	SetEvent((HANDLE)dwCallBack);
+	break;
+    case 6: /* I would dub it DCB_MMTHREADSIGNAL */
+	/* this is an undocumented DCB_ value used for mmThreads
+	 * loword of dwCallBack contains the handle of the lpMMThd block
+	 * which dwSignalCount has to be incremented
+	 */
+	{
+	    WINE_MMTHREAD*	lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(LOWORD(dwCallBack), 0);
+
+	    TRACE(mmsys, "mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
+	    /* same as mmThreadSignal16 */
+	    InterlockedIncrement(&lpMMThd->dwSignalCount);
+	    SetEvent(lpMMThd->hEvent);
+	    /* some other stuff on lpMMThd->hVxD */
+	}
+	break;	
+#if 0
+    case 4:
+	/* this is an undocumented DCB_ value for... I don't know */
+	break;
+#endif
     default:
-	WARN(mmsys, "Unknown callback type\n");
+	WARN(mmsys, "Unknown callback type %d\n", uFlags & DCB_TYPEMASK);
 	return FALSE;
     }
     TRACE(mmsys, "Done\n");
@@ -1364,7 +1387,7 @@
  */
 DWORD WINAPI mciGetDriverData(UINT uDeviceID) 
 {
-    TRACE(mmsys,"(%04x)\n", uDeviceID);
+    TRACE(mmsys, "(%04x)\n", uDeviceID);
     if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0) {
 	WARN(mmsys, "Bad uDeviceID\n");
 	return 0L;
@@ -1411,7 +1434,7 @@
     LPBYTE          lmem;
     static UINT16   mcidevtype = 0;
     
-    FIXME(mmsys,"(%04x, %s, %d): stub!\n", hinst, resname, type);
+    FIXME(mmsys, "(%04x, %s, %d): stub!\n", hinst, resname, type);
     if (!lstrcmpiA(resname, "core")) {
 	FIXME(mmsys, "(...,\"core\",...), have to use internal tables... (not there yet)\n");
 	return 0;
@@ -1421,7 +1444,7 @@
      * otherwise directly from driver
      */
     strcpy(buf,resname);
-    strcat(buf,".mci");
+    strcat(buf, ".mci");
     if (OpenFile(buf, &ofs,OF_EXIST) != HFILE_ERROR) {
 	xhinst = LoadLibrary16(buf);
 	if (xhinst > 32)
@@ -1502,7 +1525,7 @@
 	    FIXME(mmsys, "unhandled MCI_ALL_DEVICE_ID\n");
 	    dwRet = MCIERR_CANNOT_USE_ALL;
 	} else {
-	    dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2);
+	    dwRet = MCI_SendCommandFrom32(wDevID, wMsg, dwParam1, dwParam2);
 	}
 	break;
     }
@@ -1516,7 +1539,8 @@
  */
 DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2)
 {
-    return 0x1; /* !ok */
+    FIXME(mmsys, "(%08x, %s, %08lx, %08lx): stub\n", wDevID, MCI_CommandToString(wMsg), dwParam1, dwParam2);
+    return MCIERR_UNSUPPORTED_FUNCTION;
 }
 
 /**************************************************************************
@@ -1531,9 +1555,13 @@
 
     switch (wMsg) {
     case MCI_OPEN:
-	if (MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2) >= 0) {
+	switch (MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2)) {
+	case MCI_MAP_OK:
+	case MCI_MAP_OKMEM:
 	    dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
 	    MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
+	    break;
+	default: break; /* so that gcc does bark */
 	}
 	break;
     case MCI_CLOSE:
@@ -1542,15 +1570,25 @@
 	    dwRet = MCIERR_CANNOT_USE_ALL;
 	} else if (!MCI_DevIDValid(wDevID)) {
 	    dwRet = MCIERR_INVALID_DEVICE_ID;
-	} else if (MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2) >= 0) {
-	    dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
-	    MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
+	} else {
+	    switch (MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2)) {
+	    case MCI_MAP_OK:
+	    case MCI_MAP_OKMEM:
+		dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
+		MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
+		break;
+	    default: break; /* so that gcc does bark */
+	    }
 	}
 	break;
     case MCI_SYSINFO:
-	if (MCI_MapMsg16To32A(0, wDevID, &dwParam2) >= 0) {
+	switch (MCI_MapMsg16To32A(0, wDevID, &dwParam2)) {
+	case MCI_MAP_OK:
+	case MCI_MAP_OKMEM:
 	    dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2);
 	    MCI_UnMapMsg16To32A(0, wDevID, dwParam2);
+	    break;
+	default: break; /* so that gcc does bark */
 	}
 	break;
     /* FIXME: it seems that MCI_BREAK and MCI_SOUND need the same handling */
@@ -1558,38 +1596,10 @@
 	if (wDevID == MCI_ALL_DEVICE_ID) {
 	    FIXME(mmsys, "unhandled MCI_ALL_DEVICE_ID\n");
 	    dwRet = MCIERR_CANNOT_USE_ALL;
-	} else if (!MCI_DevIDValid(wDevID)) {
-	    dwRet = MCIERR_INVALID_DEVICE_ID;
 	} else {
-	    int			res;
-		    
-	    switch (DRIVER_GetType(MCI_GetDrv(wDevID)->hDrv)) {
-	    case WINE_DI_TYPE_16:		
-		dwRet = SendDriverMessage16(MCI_GetDrv(wDevID)->hDrv, wMsg, dwParam1, dwParam2);
-		break;
-	    case WINE_DI_TYPE_32:
-		switch (res = MCI_MapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, &dwParam2)) {
-		case -1:
-		    TRACE(mmsys, "Not handled yet (%s)\n", MCI_CommandToString(wMsg));
-		    dwRet = MCIERR_DRIVER_INTERNAL;
-		    break;
-		case -2:
-		    TRACE(mmsys, "Problem mapping msg=%s from 16 to 32a\n", MCI_CommandToString(wMsg));
-		    dwRet = MCIERR_OUT_OF_MEMORY;
-		    break;
-		case 0:
-		case 1:
-		    dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2);
-		    if (res)
-			MCI_UnMapMsg16To32A(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam2);
-		    break;
-		}
-		break;
-	    default:
-		WARN(mmsys, "Unknown driver type=%u\n", DRIVER_GetType(MCI_GetDrv(wDevID)->hDrv));
-		dwRet = MCIERR_DRIVER_INTERNAL;
-	    }
+	    dwRet = MCI_SendCommandFrom16(wDevID, wMsg, dwParam1, dwParam2);
 	}
+	break;
     }
     dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2, FALSE);
     TRACE(mmsys, "=> %ld\n", dwRet);
@@ -1651,9 +1661,11 @@
     return ret;
 }
 
+/**************************************************************************
+ * 				MCI_DefYieldProc	       	[internal]
+ */
 UINT16	WINAPI MCI_DefYieldProc(UINT16 wDevID, DWORD data)
 {
-    MSG		msg;
     INT16	ret;
     
     TRACE(mmsys, "(0x%04x, 0x%08lx)\n", wDevID, data);
@@ -1663,8 +1675,9 @@
 	UserYield16();
 	ret = 0;
     } else {
-	msg.hwnd = HIWORD(data);
+	MSG		msg;
 
+	msg.hwnd = HIWORD(data);
 	while (!PeekMessageA(&msg, HIWORD(data), WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
 	ret = 0xFFFF;
     }
@@ -1805,7 +1818,7 @@
 {
     UINT16	ret = 0;
 
-    /*    TRACE(mmsys,"(%04x)\n", uDeviceID); */
+    /*    TRACE(mmsys, "(%04x)\n", uDeviceID); */
 
     if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0 ||
 	!MCI_GetDrv(uDeviceID)->lpfnYieldProc || MCI_GetDrv(uDeviceID)->bIs32) {
@@ -1824,7 +1837,7 @@
 {
     UINT	ret = 0;
 
-    TRACE(mmsys,"(%04x)\n", uDeviceID);
+    TRACE(mmsys, "(%04x)\n", uDeviceID);
     if (!MCI_DevIDValid(uDeviceID) || MCI_GetDrv(uDeviceID)->modp.wType == 0 ||
 	!MCI_GetDrv(uDeviceID)->lpfnYieldProc || !MCI_GetDrv(uDeviceID)->bIs32) {
 	UserYield16();
@@ -2028,6 +2041,7 @@
 UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID,
                             DWORD dwCallback, DWORD dwInstance, DWORD dwFlags)
 {
+    HMIDIOUT16			hMidiOut;
     LPMIDIOPENDESC		lpDesc;
     UINT16			ret = 0;
     BOOL			bMapperFlg = FALSE;
@@ -2043,7 +2057,7 @@
 	uDeviceID = 0;
     }
 
-    lpDesc = MIDI_OutAlloc(lphMidiOut, dwCallback, dwInstance, 0, NULL);
+    lpDesc = MIDI_OutAlloc(&hMidiOut, dwCallback, dwInstance, 0, NULL);
 
     if (lpDesc == NULL)
 	return MMSYSERR_NOMEM;
@@ -2058,10 +2072,11 @@
     }
     TRACE(mmsys, "=> wDevID=%u (%d)\n", uDeviceID, ret);
     if (ret != MMSYSERR_NOERROR) {
-	HeapFree(GetProcessHeap(), 0, lpDesc);
+	USER_HEAP_FREE(hMidiOut);
 	if (lphMidiOut) *lphMidiOut = 0;
     } else {
 	lpDesc->wDevID = uDeviceID;
+	if (lphMidiOut) *lphMidiOut = hMidiOut;
     }
 
     return ret;
@@ -2089,7 +2104,7 @@
 
     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
     dwRet = modMessage(lpDesc->wDevID, MODM_CLOSE, lpDesc->dwInstance, 0L, 0L);
-    HeapFree(GetProcessHeap(), 0, lpDesc);
+    USER_HEAP_FREE(hMidiOut);
     return dwRet;
 }
 
@@ -2340,7 +2355,7 @@
     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
     switch (uMessage) {
     case MODM_OPEN:
-	FIXME(mmsys,"can't handle MODM_OPEN!\n");
+	FIXME(mmsys, "can't handle MODM_OPEN!\n");
 	return 0;
     case MODM_GETDEVCAPS:
 	return midiOutGetDevCapsA(hMidiOut, (LPMIDIOUTCAPSA)dwParam1, dwParam2);
@@ -2355,7 +2370,7 @@
 	/* no argument conversion needed */
 	break;
     default:
-	ERR(mmsys,"(%04x, %04x, %08lx, %08lx): unhandled message\n",
+	ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
 	    hMidiOut, uMessage, dwParam1, dwParam2);
 	break;
     }
@@ -2376,7 +2391,7 @@
     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
     switch (uMessage) {
     case MODM_OPEN:
-	FIXME(mmsys,"can't handle MODM_OPEN!\n");
+	FIXME(mmsys, "can't handle MODM_OPEN!\n");
 	return 0;
     case MODM_GETNUMDEVS:
     case MODM_RESET:
@@ -2394,7 +2409,7 @@
     case MODM_UNPREPARE:
 	return midiOutUnprepareHeader16(hMidiOut, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
     default:
-	ERR(mmsys,"(%04x, %04x, %08lx, %08lx): unhandled message\n",
+	ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
 	    hMidiOut, uMessage, dwParam1, dwParam2);
 	break;
     }
@@ -2781,7 +2796,7 @@
     
     switch (uMessage) {
     case MIDM_OPEN:
-	FIXME(mmsys,"can't handle MIDM_OPEN!\n");
+	FIXME(mmsys, "can't handle MIDM_OPEN!\n");
 	return 0;
     case MIDM_GETDEVCAPS:
 	return midiInGetDevCapsA(hMidiIn, (LPMIDIINCAPSA)dwParam1, dwParam2);
@@ -2799,7 +2814,7 @@
     case MIDM_ADDBUFFER:
 	return midiInAddBuffer(hMidiIn, (LPMIDIHDR)dwParam1, dwParam2);
     default:
-	ERR(mmsys,"(%04x, %04x, %08lx, %08lx): unhandled message\n",
+	ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
 	    hMidiIn, uMessage, dwParam1, dwParam2);
 	break;
     }
@@ -2820,7 +2835,7 @@
     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
     switch (uMessage) {
     case MIDM_OPEN:
-	WARN(mmsys,"can't handle MIDM_OPEN!\n");
+	WARN(mmsys, "can't handle MIDM_OPEN!\n");
 	return 0;
     case MIDM_GETDEVCAPS:
 	return midiInGetDevCaps16(hMidiIn, (LPMIDIINCAPS16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
@@ -2838,7 +2853,7 @@
     case MIDM_ADDBUFFER:
 	return midiInAddBuffer16(hMidiIn, (LPMIDIHDR16)PTR_SEG_TO_LIN(dwParam1), dwParam2);
     default:
-	ERR(mmsys,"(%04x, %04x, %08lx, %08lx): unhandled message\n",
+	ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
 	    hMidiIn, uMessage, dwParam1, dwParam2);
 	break;
     }
@@ -3070,7 +3085,7 @@
 
     midiStreamStop(hMidiStrm);
 
-    HeapFree(GetProcessHeap(), 0, lpMidiStrm);
+    USER_HEAP_FREE(hMidiStrm);
 
     return midiOutClose(hMidiStrm);
 }
@@ -3971,10 +3986,10 @@
 	/* FIXME: UNICODE/ANSI? */
 	return waveOutGetDevCapsA(hWaveOut, (LPWAVEOUTCAPSA)dwParam1, dwParam2);
     case WODM_OPEN:
-	FIXME(mmsys,"can't handle WODM_OPEN, please report.\n");
+	FIXME(mmsys, "can't handle WODM_OPEN, please report.\n");
 	break;
     default:
-	ERR(mmsys,"(0x%04x, 0x%04x, %08lx, %08lx): unhandled message\n",
+	ERR(mmsys, "(0x%04x, 0x%04x, %08lx, %08lx): unhandled message\n",
 	    hWaveOut, uMessage, dwParam1, dwParam2);
 	break;
     }
@@ -4019,10 +4034,10 @@
     case WODM_WRITE:
 	return waveOutWrite16(hWaveOut, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
     case WODM_OPEN:
-	FIXME(mmsys,"can't handle WODM_OPEN, please report.\n");
+	FIXME(mmsys, "can't handle WODM_OPEN, please report.\n");
 	break;
     default:
-	ERR(mmsys,"(0x%04x, 0x%04x, %08lx, %08lx): unhandled message\n",
+	ERR(mmsys, "(0x%04x, 0x%04x, %08lx, %08lx): unhandled message\n",
 	    hWaveOut, uMessage, dwParam1, dwParam2);
     }
     return wodMessage(lpDesc->uDeviceID, uMessage, lpDesc->dwInstance, dwParam1, dwParam2);
@@ -4181,8 +4196,7 @@
     if (dwFlags & WAVE_FORMAT_QUERY) {
 	TRACE(mmsys, "End of WAVE_FORMAT_QUERY !\n");
 	dwRet = waveInClose16(hWaveIn);
-    }
-    else if (dwRet != MMSYSERR_NOERROR) {
+    } else if (dwRet != MMSYSERR_NOERROR) {
 	USER_HEAP_FREE(hWaveIn);
 	if (lphWaveIn) *lphWaveIn = 0;
     }
@@ -4497,7 +4511,7 @@
 	/*FIXME: ANSI/UNICODE */
 	return waveInGetDevCapsA(hWaveIn, (LPWAVEINCAPSA)dwParam1, dwParam2);
     default:
-	ERR(mmsys,"(%04x, %04x, %08lx, %08lx): unhandled message\n",
+	ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
 	    hWaveIn, uMessage, dwParam1, dwParam2);
 	break;
     }
@@ -4518,7 +4532,7 @@
     if (lpDesc == NULL) return MMSYSERR_INVALHANDLE;
     switch (uMessage) {
     case WIDM_OPEN:
-	FIXME(mmsys,"cannot handle WIDM_OPEN, please report.\n");
+	FIXME(mmsys, "cannot handle WIDM_OPEN, please report.\n");
 	break;
     case WIDM_GETNUMDEVS:
     case WIDM_CLOSE:
@@ -4539,7 +4553,7 @@
     case WIDM_ADDBUFFER:
 	return waveInAddBuffer16(hWaveIn, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
     default:
-	ERR(mmsys,"(%04x, %04x, %08lx, %08lx): unhandled message\n",
+	ERR(mmsys, "(%04x, %04x, %08lx, %08lx): unhandled message\n",
 	    hWaveIn, uMessage, dwParam1, dwParam2);
 	break;
     }
@@ -4551,7 +4565,7 @@
  */
 HDRVR16 WINAPI DrvOpen(LPSTR lpDriverName, LPSTR lpSectionName, LPARAM lParam)
 {
-    TRACE(mmsys,"('%s','%s', %08lX);\n", lpDriverName, lpSectionName, lParam);
+    TRACE(mmsys, "('%s','%s', %08lX);\n", lpDriverName, lpSectionName, lParam);
 
     return OpenDriver16(lpDriverName, lpSectionName, lParam);
 }
@@ -4613,6 +4627,8 @@
     }
 }
 
+/*#define USE_MM_TSK_WINE*/
+
 /**************************************************************************
  * 				mmTaskCreate		[MMSYSTEM.900]
  *
@@ -4629,13 +4645,21 @@
     HINSTANCE16		handle;
     
     TRACE(mmsys, "(%08lx, %p, %08lx);\n", spProc, lphMmTask, dwPmt);
+    /* This to work requires NE modules to be started with a binary command line
+     * which is not currently the case. A patch exists but has never been committed.
+     * A workaround would be to integrate code for mmtask.tsk into Wine, but
+     * this requires tremendous work (starting with patching tools/build to
+     * create NE executables (and not only DLLs) for builtins modules.
+     * EP 99/04/25
+     */
+    FIXME(mmsys, "This is currently broken. It will fail\n");
 
     cmdline = (LPSTR)HeapAlloc(GetProcessHeap(), 0, 0x0d);
     cmdline[0] = 0x0d;
     *(LPDWORD)(cmdline + 1) = (DWORD)spProc;
     *(LPDWORD)(cmdline + 5) = dwPmt;
     *(LPDWORD)(cmdline + 9) = 0;
-    
+
     sel1 = SELECTOR_AllocBlock(cmdline, 0x0d, SEGMENT_DATA, FALSE, FALSE);
     sel2 = SELECTOR_AllocBlock(&showCmd, sizeof(showCmd),
 			       SEGMENT_DATA, FALSE, FALSE);
@@ -4646,7 +4670,11 @@
     lp->showCmd = PTR_SEG_OFF_TO_SEGPTR(sel2, 0);
     lp->reserved = 0;
     
+#ifndef USE_MM_TSK_WINE
     handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", lp);
+#else
+    handle = LoadModule16("mmtask.tsk", lp);
+#endif
     if (handle < 32) {
 	ret = (handle) ? 1 : 2;
 	handle = 0;
@@ -4666,23 +4694,25 @@
     return ret;
 }
 
-#if 0
+#ifdef USE_MM_TSK_WINE
 /* C equivalent to mmtask.tsk binary content */
-void	mmTaskEntryPoint(LPSTR cmdLine, WORD di, WORD si)
+void	mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si)
 {
     int	len = cmdLine[0x80];
 
     if (len/2 == 6) {
-	void	(*fpProc)(DWORD) = (void (*)(DWORD))SEG_PTR_TO_LIN(*((DWORD*)(cmdLine + 1)));
+	void	(*fpProc)(DWORD) = (void (*)(DWORD))PTR_SEG_TO_LIN(*((DWORD*)(cmdLine + 1)));
 	DWORD	dwPmt  = *((DWORD*)(cmdLine + 5));
 
+#if 0
 	InitTask16(); /* fixme: pmts / from context ? */
 	InitApp(di);
+#endif
 	if (SetMessageQueue16(0x40)) {
 	    WaitEvent16(0);
 	    if (HIWORD(fpProc)) {
 		OldYield16();
-		StackEnter16();
+/* EPP 		StackEnter16(); */
 		(fpProc)(dwPmt);
 	    }
 	}
@@ -4715,7 +4745,7 @@
  */
 LRESULT	WINAPI mmTaskSignal16(HTASK16 ht) 
 {
-    TRACE(mmsys,"(%04x);\n", ht);
+    TRACE(mmsys, "(%04x);\n", ht);
     return Callout.PostAppMessage16(ht, WM_USER, 0, 0);
 }
 
@@ -4731,20 +4761,23 @@
     }
 }
 
-void	WINAPI	WINE_mmThreadingEntryPoint(DWORD _pmt);
-
 DWORD	WINAPI	GetProcessFlags(DWORD);
 
 /**************************************************************************
  * 				mmThreadCreate		[MMSYSTEM.1120]
+ *
+ * undocumented
+ * Creates a MM thread, calling fpThreadAddr(dwPmt). 
+ * dwFlags: 
+ * 	bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc
+ *	bit.1 set means to open a VxD for this thread (unsupported) 
  */
 LRESULT	WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE lpHndl, DWORD dwPmt, DWORD dwFlags) 
 {
     HANDLE16		hndl;
     LRESULT		ret;
-    FARPROC16		fp;
 
-    FIXME(mmsys, "(%p, %p, %08lx, %08lx): semi-stub!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags);
+    TRACE(mmsys, "(%p, %p, %08lx, %08lx)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags);
 
     hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT);
 
@@ -4753,71 +4786,81 @@
     } else {
 	WINE_MMTHREAD*	lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
 
-	lpMMThd->dwSignature = WINE_MMTHREAD_CREATED;
-	lpMMThd->dwCounter   = 0;
-	lpMMThd->hThread     = 0;
-	lpMMThd->dwThreadId  = 0;
-	lpMMThd->fpThread    = fpThreadAddr;
-	lpMMThd->dwThreadPmt = dwPmt;
-	/* FIXME     lpMMThd->dwUnknown3; */
-	lpMMThd->hEvent = 0;
-	/* FIXME     lpMMThd->dwUnknown5; */
-	lpMMThd->dwStatus    = 0;
-	lpMMThd->dwFlags     = dwFlags;
-	lpMMThd->hTask       = 0;
-
-	/* FIXME: Since main task in Wine is 16 bit (not 32, which is the case for 
-	 * win 9x the test below may not work.
-	 */
-#ifdef WINE_MAIN_TASK_IS_32BIT
-	if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) != 0)
-	    FIXME(mmsys, "(NIY) Oooch: seems to require a real thread, not a 16 bit task !!\n");
-#else
-	if ((dwFlags & 1) == 0) 
-	    FIXME(mmsys, "(NIY) Oooch: seems to require a real thread, not a 16 bit task !!\n");
-#endif
-
 #if 0
-	if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8)) {
-	    leavewin16lock();
-	    lpMMThd->hEvent = CreateEventA(0, 0, 1, 0);
-	    if (lpMMThd->dwFlags & 2)
-		lpMMThd->dwUnknown5 = OpenVxDHandle(lpMMThd->hEvent);
-	    if (!CreateThread(0, 0, proc, SEGPTR(hndl, 0), 4, x)) {
-		clean-up(event, VxDhandle...);
-	    } else {
-		lpMMThd->hThread = return from CreateThread;
-	    }
-	}
-	else; /* do what's below */
+	/* force mmtask routines even if mmthread is required */
+	/* this will work only if the patch about binary cmd line and NE tasks 
+	 * is committed
+	 */
+	dwFlags |= 1;
 #endif
 
-	/* get WINE_mmThreadingEntryPoint() 
-	 * 2047 is its ordinal in mmsystem.spec
-	 */
-	fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (SEGPTR)2047);
-	TRACE(mmsys, "farproc seg=0x%08lx lin=%p\n", (DWORD)fp, PTR_SEG_TO_LIN(fp));
+	lpMMThd->dwSignature 	= WINE_MMTHREAD_CREATED;
+	lpMMThd->dwCounter   	= 0;
+	lpMMThd->hThread     	= 0;
+	lpMMThd->dwThreadID  	= 0;
+	lpMMThd->fpThread    	= fpThreadAddr;
+	lpMMThd->dwThreadPmt 	= dwPmt;
+	lpMMThd->dwSignalCount	= 0;
+	lpMMThd->hEvent      	= 0;
+	lpMMThd->hVxD        	= 0;
+	lpMMThd->dwStatus    	= 0;
+	lpMMThd->dwFlags     	= dwFlags;
+	lpMMThd->hTask       	= 0;
+	
+	if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) {
+	    lpMMThd->hEvent = CreateEventA(0, 0, 1, 0);
 
-	if (fp == 0 || mmTaskCreate16((DWORD)fp, 0, hndl) != 0) {
-	    GlobalFree16(hndl);
-	    hndl = 0;
-	    ret = 1;
+	    TRACE(mmsys, "Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd);
+	    if (lpMMThd->dwFlags & 2) {
+		/* as long as we don't support MM VxD in wine, we don't need 
+		 * to care about this flag
+		 */
+		/* FIXME(mmsys, "Don't know how to properly open VxD handles\n"); */
+		/* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */
+	    }
+
+	    lpMMThd->hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)WINE_mmThreadEntryPoint, 
+					    (LPVOID)(DWORD)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID);
+	    if (lpMMThd->hThread == 0) {
+		WARN(mmsys, "Couldn't create thread\n");
+		/* clean-up(VxDhandle...); devicedirectio... */
+		if (lpMMThd->hEvent != 0)
+		    CloseHandle(lpMMThd->hEvent);
+		ret = 2;
+	    } else {
+		TRACE(mmsys, "Got a nice thread hndl=0x%04x id=0x%08lx\n", lpMMThd->hThread, lpMMThd->dwThreadID);
+		ret = 0;
+	    }
 	} else {
-	    ret = 0;
-	    while (lpMMThd->dwStatus < 10) {
+	    /* get WINE_mmThreadEntryPoint() 
+	     * 2047 is its ordinal in mmsystem.spec
+	     */
+	    FARPROC16	fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (SEGPTR)2047);
+
+	    TRACE(mmsys, "farproc seg=0x%08lx lin=%p\n", (DWORD)fp, PTR_SEG_TO_LIN(fp));
+
+	    ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl);
+	}
+
+	if (ret == 0) {
+	    if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread))
+		WARN(mmsys, "Couldn't resume thread\n");
+
+	    while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */
 		UserYield16();
 	    }
 	}
     }
-#if 0
-    if (lpMMThd->hThread)
-	ResumeThread(lpMMThd->hThread);
-#endif
 
+    if (ret != 0) {
+	GlobalFree16(hndl);
+	hndl = 0;
+    }
 
     if (lpHndl)
 	*lpHndl = hndl;
 
+    TRACE(mmsys, "ok => %ld\n", ret);
     return ret;
 }
 
@@ -4826,75 +4869,99 @@
  */
 void WINAPI mmThreadSignal16(HANDLE16 hndl) 
 {
-    TRACE(mmsys,"(%04x)!\n", hndl);
+    TRACE(mmsys, "(%04x)!\n", hndl);
 
     if (hndl) {
 	WINE_MMTHREAD*	lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
 
 	lpMMThd->dwCounter++;
-#if 0
 	if (lpMMThd->hThread != 0) {
-	    /* FIXME ??
-	     * SYSLEVEL_ReleaseWin16Lock();
-	     * InterlockedIncrement(lpMMThd->hThread [18]);
-	     * SetEvent(lpMMThd->hThread [1C]);
-	     * SYSLEVEL_RestoreWin16Lock();
-	     */
+	    InterlockedIncrement(&lpMMThd->dwSignalCount);
+	    SetEvent(lpMMThd->hEvent);
 	} else {
 	    mmTaskSignal16(lpMMThd->hTask);
 	}
-#else
-	mmTaskSignal16(lpMMThd->hTask);
-#endif
 	lpMMThd->dwCounter--;
     }
 }
 
 /**************************************************************************
+ * 				MMSYSTEM_ThreadBlock		[internal]
+ */
+static	void	MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd)
+{
+    MSG		msg;
+    DWORD	ret;
+
+    if (lpMMThd->dwThreadID != GetCurrentThreadId())
+	ERR(mmsys, "Not called by thread itself\n");
+
+    for (;;) {
+	ResetEvent(lpMMThd->hEvent);
+	if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0)
+	    break;
+	InterlockedIncrement(&lpMMThd->dwSignalCount);
+	
+	TRACE(mmsys, "S1\n");
+	
+	ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT);
+	switch (ret) {
+	case WAIT_OBJECT_0:	/* Event */
+	    TRACE(mmsys, "S2.1\n");
+	    break;
+	case WAIT_OBJECT_0 + 1:	/* Msg */
+	    TRACE(mmsys, "S2.2\n");
+	    if (Callout.PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
+		Callout.TranslateMessage(&msg);
+		Callout.DispatchMessageA(&msg);
+	    }
+	    break;
+	default:
+	    WARN(mmsys, "S2.x unsupported ret val 0x%08lx\n", ret);
+	}
+	TRACE(mmsys, "S3\n");
+    }
+}
+
+/**************************************************************************
  * 				mmThreadBlock		[MMSYSTEM.1122]
  */
 void	WINAPI mmThreadBlock16(HANDLE16 hndl) 
 {
-    TRACE(mmsys,"(%04x)!\n", hndl);
+    TRACE(mmsys, "(%04x)!\n", hndl);
 
     if (hndl) {
 	WINE_MMTHREAD*	lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
 	
-#if 0
 	if (lpMMThd->hThread != 0) {
-	    /* FIXME
-	     * DPMI: lock linear region lpMMThd
-	     */
+	    SYSLEVEL_ReleaseWin16Lock();
+	    MMSYSTEM_ThreadBlock(lpMMThd);
+	    SYSLEVEL_RestoreWin16Lock();
 	} else {
 	    mmTaskBlock16(lpMMThd->hTask);
 	}
-#else
-	mmTaskBlock16(lpMMThd->hTask);
-#endif
     }
+    TRACE(mmsys, "done\n");
 }
 
-HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl);
-BOOL16	 WINAPI	mmThreadIsValid16(HANDLE16 hndl);
-
 /**************************************************************************
  * 				mmThreadIsCurrent	[MMSYSTEM.1123]
  */
 BOOL16	WINAPI mmThreadIsCurrent16(HANDLE16 hndl) 
 {
-    WINE_MMTHREAD*	lpMMThd;
+    BOOL16		ret = FALSE;
 
-    TRACE(mmsys, "(%04x)! stub\n", hndl);
+    TRACE(mmsys, "(%04x)!\n", hndl);
 
-    if (!hndl)
-	return FALSE;
-
-    if (!mmThreadIsValid16(hndl))
-	return FALSE;
-
-    lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
-
-    return GetCurrentThreadId() == lpMMThd->dwThreadId;
+    if (hndl && mmThreadIsValid16(hndl)) {
+	WINE_MMTHREAD*	lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
+	ret = (GetCurrentThreadId() == lpMMThd->dwThreadID);
+	/* FIXME: just a test */
+	SYSLEVEL_ReleaseWin16Lock();
+	SYSLEVEL_RestoreWin16Lock();
+    }
+    TRACE(mmsys, "=> %d\n", ret);
+    return ret;
 }
 
 /**************************************************************************
@@ -4902,34 +4969,30 @@
  */
 BOOL16	WINAPI	mmThreadIsValid16(HANDLE16 hndl)
 {
-    WINE_MMTHREAD*	lpMMThd;
-    BOOL16		ret = TRUE;
+    BOOL16		ret = FALSE;
 
     TRACE(mmsys, "(%04x)!\n", hndl);
 
-    if (!hndl)
-	return FALSE;
-    lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
+    if (hndl) {
+	WINE_MMTHREAD*	lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
 
-    if (IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) ||
-	lpMMThd->dwSignature != WINE_MMTHREAD_CREATED ||
-	!IsTask16(lpMMThd->hTask))
-	return FALSE;
-
-#if 0
-    lpMMThd->dwCounter++;
-    if (lpMMThd->hThread != 0) {
-	DWORD	dwThreadRet;
-
-	SYSLEVEL_ReleaseWin16Lock();
-	if (!GetExitCodeThread(lpMMThd->hThread, &locvar) ||
-	    dwThreadRet != STATUS_PENDING) {
-	    ret = FALSE;
+	if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) &&
+	    lpMMThd->dwSignature == WINE_MMTHREAD_CREATED &&
+	    IsTask16(lpMMThd->hTask)) {
+	    lpMMThd->dwCounter++;
+	    if (lpMMThd->hThread != 0) {
+		DWORD	dwThreadRet;
+		if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) &&
+		    dwThreadRet == STATUS_PENDING) {
+		    ret = TRUE;
+		}
+	    } else {
+		ret = TRUE;
+	    }
+	    lpMMThd->dwCounter--;
 	}
-	SYSLEVEL_RestoreWin16Lock();
     }
-    lpMMThd->dwCounter--;
-#endif
+    TRACE(mmsys, "=> %d\n", ret);
     return ret;
 }
 
@@ -4940,7 +5003,7 @@
 {
     HANDLE16	ret = 0;
 
-    TRACE(mmsys,"(%04x)\n", hndl);
+    TRACE(mmsys, "(%04x)\n", hndl);
 
     if (mmThreadIsValid16(hndl)) {
 	WINE_MMTHREAD*	lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
@@ -4949,49 +5012,82 @@
     return ret;
 }
 
-void	WINAPI	WINE_mmThreadingEntryPoint(DWORD _pmt)
+/**************************************************************************
+ * 				mmThreadGetTask			[internal]
+ */
+void	WINAPI	WINE_mmThreadEntryPoint(DWORD _pmt)
 {
     HANDLE16		hndl = (HANDLE16)_pmt;
     WINE_MMTHREAD*	lpMMThd = (WINE_MMTHREAD*)PTR_SEG_OFF_TO_LIN(hndl, 0);
+    CRITICAL_SECTION*	cs;
 
     TRACE(mmsys, "(%04x %p)\n", hndl, lpMMThd);
 
+    GetpWin16Lock(&cs);
+
+    TRACE(mmsys, "lc=%ld rc=%ld ot=%08lx\n", cs->LockCount, cs->RecursionCount, (DWORD)cs->OwningThread);
+
     lpMMThd->hTask = LOWORD(GetCurrentTask());
+    TRACE(mmsys, "[10-%08x] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask);
     lpMMThd->dwStatus = 0x10;
-    mmThreadBlock16(hndl);
+    MMSYSTEM_ThreadBlock(lpMMThd);
+    TRACE(mmsys, "[20-%08x]\n", lpMMThd->hThread);
     lpMMThd->dwStatus = 0x20;
-    if (lpMMThd->fpThread) 
+    if (lpMMThd->fpThread) {
+#if 0
+        extern	DWORD	CALLBACK	CallTo16_long_l_x(FARPROC16, DWORD);
+	TRACE(mmsys, "Calling %08lx(%08lx)\n", (DWORD)lpMMThd->fpThread, lpMMThd->dwThreadPmt);$
+	CallTo16_long_l_x(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
+#else
 	Callbacks->CallWOWCallbackProc(lpMMThd->fpThread, lpMMThd->dwThreadPmt);
-    lpMMThd->dwStatus = 0x30;
-    while (lpMMThd->dwCounter) {
-	Yield16();
+#endif
     }
+    lpMMThd->dwStatus = 0x30;
+    TRACE(mmsys, "[30-%08x]\n", lpMMThd->hThread);
+    while (lpMMThd->dwCounter) {
+	Sleep(1);
+	/* Yield16();*/
+    }
+    TRACE(mmsys, "[XX-%08x]\n", lpMMThd->hThread);
+    /* paranoia */
     lpMMThd->dwSignature = WINE_MMTHREAD_DELETED;
+    /* close lpMMThread->hVxD directio */
+    if (lpMMThd->hEvent)
+	CloseHandle(lpMMThd->hEvent);
     GlobalFree16(hndl);
+    TRACE(mmsys, "lc=%ld rc=%ld ot=%08lx\n", cs->LockCount, cs->RecursionCount, (DWORD)cs->OwningThread);
+    TRACE(mmsys, "done\n");
 }
 
 /**************************************************************************
  * 			mmShowMMCPLPropertySheet	[MMSYSTEM.1150]
  */
-BOOL16	WINAPI	mmShowMMCPLPropertySheet16(WORD w1, WORD w2, WORD w3, WORD w4, WORD w5, WORD w6, WORD w7)
+BOOL16	WINAPI	mmShowMMCPLPropertySheet16(HWND hWnd, char* lpStrDevice, 
+					   char* lpStrTab, char* lpStrTitle)
 {
-    FIXME(mmsys, "(%04x %04x %04x %04x %04x %04x %04x): stub!\n", w1, w2, w3, w4, w5, w6, w7);
-
-#if 0
     HANDLE	hndl;
-    FARPROC	fp;
     BOOL16	ret = FALSE;
 
-    /* to be tested */
-    if ((hndl = LoadLibraryA("MMSYS.CPL")) != 0) {
-	if ((fp = GetProcAddressA(hndl, "ShowMMCPLPropertySheet")) != NULL) {
-	    ret = ((BOOL16 (WINAPI *)(WORD, WORD, WORD, WORD, WORD, WORD, WORD, WORD))fp)(0, w1, w2, w3, w4, w5, w6, w7);
+    TRACE(mmsys, "(%04x \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle);
+
+    hndl = LoadLibraryA("MMSYS.CPL");
+    if (hndl != 0) {
+	BOOL16 (WINAPI *fp)(HWND, LPSTR, LPSTR, LPSTR);
+
+	fp = (BOOL16 (WINAPI *)(HWND, LPSTR, LPSTR, LPSTR))GetProcAddress(hndl, "ShowMMCPLPropertySheet");
+	if (fp != NULL) {	    
+	    /* FIXME: wine hangs and/or seg faults in this call, 
+	     * after the window is correctly displayed 
+	     */
+	    TRACE(mmsys, "Ready to go ThreadID=%08lx\n", GetCurrentThreadId());
+	    SYSLEVEL_ReleaseWin16Lock();
+	    ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle);
+	    SYSLEVEL_RestoreWin16Lock();
 	}
-	FreeLibraryA(hndl);
+	FreeLibrary(hndl);
     }
-#endif
     
-    return TRUE;
+    return ret;
 }
 
 /**************************************************************************
diff --git a/relay32/.cvsignore b/relay32/.cvsignore
index dc01b36..b2ad281 100644
--- a/relay32/.cvsignore
+++ b/relay32/.cvsignore
@@ -16,6 +16,11 @@
 imm32.c
 kernel32.c
 lz32.c
+mcianim.c
+mciavi.c
+mcicda.c
+mciseq.c
+mciwave.c
 mpr.c
 msacm32.c
 msnet32.c
diff --git a/relay32/Makefile.in b/relay32/Makefile.in
index ab6e02a..e84e3a6 100644
--- a/relay32/Makefile.in
+++ b/relay32/Makefile.in
@@ -23,6 +23,11 @@
 	kernel32.spec \
 	lz32.spec \
 	mpr.spec \
+	mcianim.spec \
+	mciavi.spec \
+	mcicda.spec \
+	mciseq.spec \
+	mciwave.spec \
 	msacm32.spec \
 	msnet32.spec \
 	msvfw32.spec \
diff --git a/relay32/builtin32.c b/relay32/builtin32.c
index 5107da0..d642d26 100644
--- a/relay32/builtin32.c
+++ b/relay32/builtin32.c
@@ -63,6 +63,11 @@
 extern const BUILTIN32_DESCRIPTOR KERNEL32_Descriptor;
 extern const BUILTIN32_DESCRIPTOR LZ32_Descriptor;
 extern const BUILTIN32_DESCRIPTOR MPR_Descriptor;
+extern const BUILTIN32_DESCRIPTOR MCIAVI_Descriptor;
+extern const BUILTIN32_DESCRIPTOR MCIANIM_Descriptor;
+extern const BUILTIN32_DESCRIPTOR MCICDA_Descriptor;
+extern const BUILTIN32_DESCRIPTOR MCISEQ_Descriptor;
+extern const BUILTIN32_DESCRIPTOR MCIWAVE_Descriptor;
 extern const BUILTIN32_DESCRIPTOR MSACM32_Descriptor;
 extern const BUILTIN32_DESCRIPTOR MSNET32_Descriptor;
 extern const BUILTIN32_DESCRIPTOR MSVFW32_Descriptor;
@@ -108,6 +113,11 @@
     { &IMM32_Descriptor,    0, NULL },
     { &KERNEL32_Descriptor, 0, NULL },
     { &LZ32_Descriptor,     0, NULL },
+    { &MCIANIM_Descriptor,  0, NULL },
+    { &MCIAVI_Descriptor,   0, NULL },
+    { &MCICDA_Descriptor,   0, NULL },
+    { &MCISEQ_Descriptor,   0, NULL },
+    { &MCIWAVE_Descriptor,  0, NULL },
     { &MPR_Descriptor,      0, NULL },
     { &MSACM32_Descriptor,  0, NULL },
     { &MSNET32_Descriptor,  0, NULL },
diff --git a/relay32/mcianim.spec b/relay32/mcianim.spec
new file mode 100644
index 0000000..0e3bbb6
--- /dev/null
+++ b/relay32/mcianim.spec
@@ -0,0 +1,5 @@
+name mcianim
+file mcianim.drv
+type win32
+
+  1 stdcall DriverProc(long long long long long) MCIANIM_DriverProc
diff --git a/relay32/mciavi.spec b/relay32/mciavi.spec
new file mode 100644
index 0000000..1791b4c
--- /dev/null
+++ b/relay32/mciavi.spec
@@ -0,0 +1,5 @@
+name mciavi
+file mciavi.drv
+type win32
+
+  1 stdcall DriverProc(long long long long long) MCIAVI_DriverProc
diff --git a/relay32/mcicda.spec b/relay32/mcicda.spec
new file mode 100644
index 0000000..ad8dc72
--- /dev/null
+++ b/relay32/mcicda.spec
@@ -0,0 +1,5 @@
+name mcicda
+file mcicda.drv
+type win32
+
+  1 stdcall DriverProc(long long long long long) MCICDAUDIO_DriverProc
diff --git a/relay32/mciseq.spec b/relay32/mciseq.spec
new file mode 100644
index 0000000..2d7f5d8
--- /dev/null
+++ b/relay32/mciseq.spec
@@ -0,0 +1,5 @@
+name mciseq
+file mciseq.drv
+type win32
+
+  1 stdcall DriverProc(long long long long long) MCIMIDI_DriverProc
diff --git a/relay32/mciwave.spec b/relay32/mciwave.spec
new file mode 100644
index 0000000..63331a8
--- /dev/null
+++ b/relay32/mciwave.spec
@@ -0,0 +1,5 @@
+name mciwave
+file mciwave.drv
+type win32
+
+  1 stdcall DriverProc(long long long long long) MCIWAVE_DriverProc
diff --git a/relay32/winmm.spec b/relay32/winmm.spec
index 7dd5266..1428dc7 100644
--- a/relay32/winmm.spec
+++ b/relay32/winmm.spec
@@ -1,5 +1,6 @@
 name winmm
 type win32
+init WINMM_LibMain
 
   1 stdcall PlaySoundA(ptr long long) PlaySoundA
   2 stdcall WINMM_2(ptr long long) PlaySoundA
diff --git a/wine.ini b/wine.ini
index 467e26c..a6d772d 100644
--- a/wine.ini
+++ b/wine.ini
@@ -88,6 +88,9 @@
 ddraw, dinput, dsound	= builtin, native
 winmm, mmsystem         = builtin
 msvideo, msvfw32        = builtin, native
+mcicda.drv, mciseq.drv  = builtin, native
+mciwave.drv		= builtin, native
+mciavi.drv, mcianim.drv = native, builtin
 w32skrnl                = builtin
 wnaspi32, wow32		= builtin
 system, display, wprocs	= builtin