xref: /reactos/dll/win32/winmm/midimap/midimap.c (revision f18111b6)
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * Wine MIDI mapper driver
4  *
5  * Copyright 	1999, 2000, 2001 Eric Pouech
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  * TODO:
22  *	notification has to be implemented
23  *	IDF file loading
24  */
25 
26 #include <stdarg.h>
27 //#include <string.h>
28 //#include <stdlib.h>
29 //#include <ctype.h>
30 #include <windef.h>
31 //#include "winbase.h"
32 //#include "wingdi.h"
33 #include <winuser.h>
34 #include <mmddk.h>
35 #include <winreg.h>
36 #include <wine/unicode.h>
37 #include <wine/debug.h>
38 
39 /*
40  * Here's how Windows stores the midiOut mapping information.
41  *
42  * Full form (in HKU) is:
43  *
44  * [Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap] 988836060
45  * "AutoScheme"=dword:00000000
46  * "ConfigureCount"=dword:00000004
47  * "CurrentInstrument"="Wine OSS midi"
48  * "CurrentScheme"="epp"
49  * "DriverList"=""
50  * "UseScheme"=dword:00000000
51  *
52  * AutoScheme: 		?
53  * CurrentInstrument: 	name of midiOut device to use when UseScheme is 0. Wine uses an extension
54  *			of the form #n to link to n'th midiOut device of the system
55  * CurrentScheme:	when UseScheme is non null, it's the scheme to use (see below)
56  * DriverList:		?
57  * UseScheme:		trigger for simple/complex mapping
58  *
59  * A scheme is defined (in HKLM) as:
60  *
61  * [System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Schemes\\<nameScheme>]
62  * <nameScheme>:	one key for each defined scheme (system wide)
63  * under each one of these <nameScheme> keys, there's:
64  * [...\\<nameScheme>\\<idxDevice>]
65  * "Channels"="<bitMask>"
66  * (the default value of this key also refers to the name of the device).
67  *
68  * this defines, for each midiOut device (identified by its index in <idxDevice>), which
69  * channels have to be mapped onto it. The <bitMask> defines the channels (from 0 to 15)
70  * will be mapped (mapping occurs for channel <ch> if bit <ch> is set in <bitMask>
71  *
72  * Further mapping information can also be defined in:
73  * [System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Ports\\<nameDevice>\\Instruments\\<idx>]
74  * "Definition"="<.idf file>"
75  * "FriendlyName"="#for .idx file#"
76  * "Port"="<idxPort>"
77  *
78  * This last part isn't implemented (.idf file support).
79  */
80 
81 WINE_DEFAULT_DEBUG_CHANNEL(msacm);
82 
83 typedef struct tagMIDIOUTPORT
84 {
85     WCHAR		name[MAXPNAMELEN];
86     int			loaded;
87     HMIDIOUT		hMidi;
88     unsigned short	uDevID;
89     LPBYTE		lpbPatch;
90     unsigned int	aChn[16];
91 } MIDIOUTPORT;
92 
93 typedef	struct tagMIDIMAPDATA
94 {
95     struct tagMIDIMAPDATA*	self;
96     MIDIOUTPORT*	ChannelMap[16];
97 } MIDIMAPDATA;
98 
99 static	MIDIOUTPORT*	midiOutPorts;
100 static  unsigned	numMidiOutPorts;
101 
MIDIMAP_IsBadData(MIDIMAPDATA * mm)102 static	BOOL	MIDIMAP_IsBadData(MIDIMAPDATA* mm)
103 {
104     if (!IsBadReadPtr(mm, sizeof(MIDIMAPDATA)) && mm->self == mm)
105 	return FALSE;
106     TRACE("Bad midimap data (%p)\n", mm);
107     return TRUE;
108 }
109 
MIDIMAP_FindPort(const WCHAR * name,unsigned * dev)110 static BOOL	MIDIMAP_FindPort(const WCHAR* name, unsigned* dev)
111 {
112     for (*dev = 0; *dev < numMidiOutPorts; (*dev)++)
113     {
114 	TRACE("%s\n", wine_dbgstr_w(midiOutPorts[*dev].name));
115 	if (strcmpW(midiOutPorts[*dev].name, name) == 0)
116 	    return TRUE;
117     }
118     /* try the form #nnn */
119     if (*name == '#' && isdigit(name[1]))
120     {
121         const WCHAR*  ptr = name + 1;
122         *dev = 0;
123         do
124         {
125             *dev = *dev * 10 + *ptr - '0';
126         } while (isdigit(*++ptr));
127 	if (*dev < numMidiOutPorts)
128 	    return TRUE;
129     }
130     return FALSE;
131 }
132 
MIDIMAP_LoadSettingsDefault(MIDIMAPDATA * mom,const WCHAR * port)133 static BOOL	MIDIMAP_LoadSettingsDefault(MIDIMAPDATA* mom, const WCHAR* port)
134 {
135     unsigned i, dev = 0;
136 
137     if (port != NULL && !MIDIMAP_FindPort(port, &dev))
138     {
139 	ERR("Registry glitch: couldn't find midi out (%s)\n", wine_dbgstr_w(port));
140 	dev = 0;
141     }
142 
143     /* this is necessary when no midi out ports are present */
144     if (dev >= numMidiOutPorts)
145 	return FALSE;
146     /* sets default */
147     for (i = 0; i < 16; i++) mom->ChannelMap[i] = &midiOutPorts[dev];
148 
149     return TRUE;
150 }
151 
MIDIMAP_LoadSettingsScheme(MIDIMAPDATA * mom,const WCHAR * scheme)152 static BOOL	MIDIMAP_LoadSettingsScheme(MIDIMAPDATA* mom, const WCHAR* scheme)
153 {
154     HKEY	hSchemesKey, hKey, hPortKey;
155     unsigned	i, idx, dev;
156     WCHAR       buffer[256], port[256];
157     DWORD	type, size, mask;
158 
159     for (i = 0; i < 16; i++)	mom->ChannelMap[i] = NULL;
160 
161     if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
162 		    "System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Schemes",
163 		    &hSchemesKey))
164     {
165 	return FALSE;
166     }
167     if (RegOpenKeyW(hSchemesKey, scheme, &hKey))
168     {
169 	RegCloseKey(hSchemesKey);
170 	return FALSE;
171     }
172 
173     for (idx = 0; !RegEnumKeyW(hKey, idx, buffer, sizeof(buffer)); idx++)
174     {
175 	if (RegOpenKeyW(hKey, buffer, &hPortKey)) continue;
176 
177 	size = sizeof(port);
178 	if (RegQueryValueExW(hPortKey, NULL, 0, &type, (void*)port, &size)) continue;
179 
180 	if (!MIDIMAP_FindPort(port, &dev)) continue;
181 
182 	size = sizeof(mask);
183 	if (RegQueryValueExA(hPortKey, "Channels", 0, &type, (void*)&mask, &size))
184 	    continue;
185 
186 	for (i = 0; i < 16; i++)
187 	{
188 	    if (mask & (1 << i))
189 	    {
190 		if (mom->ChannelMap[i])
191 		    ERR("Quirks in registry, channel %u is mapped twice\n", i);
192 		mom->ChannelMap[i] = &midiOutPorts[dev];
193 	    }
194 	}
195     }
196 
197     RegCloseKey(hSchemesKey);
198     RegCloseKey(hKey);
199 
200     return TRUE;
201 }
202 
MIDIMAP_LoadSettings(MIDIMAPDATA * mom)203 static BOOL	MIDIMAP_LoadSettings(MIDIMAPDATA* mom)
204 {
205     HKEY 	hUserKey, hKey;
206     DWORD   err;
207     BOOL	ret;
208 
209     err = RegOpenCurrentUser(KEY_READ, &hUserKey);
210     if (err == ERROR_SUCCESS)
211     {
212         err = RegOpenKeyW(hUserKey,
213                           L"Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap",
214                           &hKey);
215         RegCloseKey(hUserKey);
216     }
217 
218     if (err != ERROR_SUCCESS)
219     {
220 	ret = MIDIMAP_LoadSettingsDefault(mom, NULL);
221     }
222     else
223     {
224 	DWORD	type, size, out;
225 	WCHAR   buffer[256];
226 
227 	ret = 2;
228 	size = sizeof(out);
229 	if (!RegQueryValueExA(hKey, "UseScheme", 0, &type, (void*)&out, &size) && out)
230 	{
231             static const WCHAR cs[] = {'C','u','r','r','e','n','t','S','c','h','e','m','e',0};
232 	    size = sizeof(buffer);
233 	    if (!RegQueryValueExW(hKey, cs, 0, &type, (void*)buffer, &size))
234 	    {
235 		if (!(ret = MIDIMAP_LoadSettingsScheme(mom, buffer)))
236 		    ret = MIDIMAP_LoadSettingsDefault(mom, NULL);
237 	    }
238 	    else
239 	    {
240 		ERR("Wrong registry: UseScheme is active, but no CurrentScheme found\n");
241 	    }
242 	}
243 	if (ret == 2)
244 	{
245             static const WCHAR ci[] = {'C','u','r','r','e','n','t','I','n','s','t','r','u','m','e','n','t',0};
246 	    size = sizeof(buffer);
247 	    if (!RegQueryValueExW(hKey, ci, 0, &type, (void*)buffer, &size) && *buffer)
248 	    {
249 		ret = MIDIMAP_LoadSettingsDefault(mom, buffer);
250 	    }
251 	    else if (!RegQueryValueExW(hKey, L"szPname", 0, &type, (void*)buffer, &size) && *buffer)
252 	    {
253 		/* Windows XP and higher setting */
254 		ret = MIDIMAP_LoadSettingsDefault(mom, buffer);
255 	    }
256 	    else
257 	    {
258 		ret = MIDIMAP_LoadSettingsDefault(mom, NULL);
259 	    }
260 	}
261     }
262     RegCloseKey(hKey);
263 
264     if (ret && TRACE_ON(msacm))
265     {
266 	unsigned	i;
267 
268 	for (i = 0; i < 16; i++)
269 	{
270 	    TRACE("chnMap[%2d] => %d\n",
271 		  i, mom->ChannelMap[i] ? mom->ChannelMap[i]->uDevID : -1);
272 	}
273     }
274     return ret;
275 }
276 
modOpen(DWORD_PTR * lpdwUser,LPMIDIOPENDESC lpDesc,DWORD dwFlags)277 static	DWORD	modOpen(DWORD_PTR *lpdwUser, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
278 {
279     MIDIMAPDATA*	mom = HeapAlloc(GetProcessHeap(), 0, sizeof(MIDIMAPDATA));
280 
281     TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags);
282 
283     if (!mom) return MMSYSERR_NOMEM;
284 
285     if (MIDIMAP_LoadSettings(mom))
286     {
287 	*lpdwUser = (DWORD_PTR)mom;
288 	mom->self = mom;
289 
290 	return MMSYSERR_NOERROR;
291     }
292     HeapFree(GetProcessHeap(), 0, mom);
293     return MIDIERR_INVALIDSETUP;
294 }
295 
modClose(MIDIMAPDATA * mom)296 static	DWORD	modClose(MIDIMAPDATA* mom)
297 {
298     UINT	i;
299     DWORD	ret = MMSYSERR_NOERROR;
300 
301     if (MIDIMAP_IsBadData(mom)) 	return MMSYSERR_ERROR;
302 
303     for (i = 0; i < 16; i++)
304     {
305 	DWORD	t;
306 	if (mom->ChannelMap[i] && mom->ChannelMap[i]->loaded > 0)
307 	{
308 	    t = midiOutClose(mom->ChannelMap[i]->hMidi);
309 	    if (t == MMSYSERR_NOERROR)
310 	    {
311 		mom->ChannelMap[i]->loaded = 0;
312 		mom->ChannelMap[i]->hMidi = 0;
313 	    }
314 	    else if (ret == MMSYSERR_NOERROR)
315 		ret = t;
316 	}
317     }
318     if (ret == MMSYSERR_NOERROR)
319 	HeapFree(GetProcessHeap(), 0, mom);
320     return ret;
321 }
322 
modLongData(MIDIMAPDATA * mom,LPMIDIHDR lpMidiHdr,DWORD_PTR dwParam2)323 static	DWORD	modLongData(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD_PTR dwParam2)
324 {
325     WORD	chn;
326     DWORD	ret = MMSYSERR_NOERROR;
327     MIDIHDR	mh;
328 
329     if (MIDIMAP_IsBadData(mom))
330 	return MMSYSERR_ERROR;
331 
332     mh = *lpMidiHdr;
333     for (chn = 0; chn < 16; chn++)
334     {
335 	if (mom->ChannelMap[chn] && mom->ChannelMap[chn]->loaded > 0)
336 	{
337 	    mh.dwFlags = 0;
338 	    midiOutPrepareHeader(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh));
339 	    ret = midiOutLongMsg(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh));
340 	    midiOutUnprepareHeader(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh));
341 	    if (ret != MMSYSERR_NOERROR) break;
342 	}
343     }
344     return ret;
345 }
346 
modData(MIDIMAPDATA * mom,DWORD_PTR dwParam)347 static	DWORD	modData(MIDIMAPDATA* mom, DWORD_PTR dwParam)
348 {
349     BYTE	lb = LOBYTE(LOWORD(dwParam));
350     WORD	chn = lb & 0x0F;
351     DWORD	ret = MMSYSERR_NOERROR;
352 
353     if (MIDIMAP_IsBadData(mom))
354 	return MMSYSERR_ERROR;
355 
356     if (!mom->ChannelMap[chn]) return MMSYSERR_NOERROR;
357 
358     switch (lb & 0xF0)
359     {
360     case 0x80:
361     case 0x90:
362     case 0xA0:
363     case 0xB0:
364     case 0xC0:
365     case 0xD0:
366     case 0xE0:
367 	if (mom->ChannelMap[chn]->loaded == 0)
368 	{
369 	    if (midiOutOpen(&mom->ChannelMap[chn]->hMidi, mom->ChannelMap[chn]->uDevID,
370 			    0L, 0L, CALLBACK_NULL) == MMSYSERR_NOERROR)
371 		mom->ChannelMap[chn]->loaded = 1;
372 	    else
373 		mom->ChannelMap[chn]->loaded = -1;
374 	    /* FIXME: should load here the IDF midi data... and allow channel and
375 	     * patch mappings
376 	     */
377 	}
378 	if (mom->ChannelMap[chn]->loaded > 0)
379 	{
380 	    /* change channel */
381 	    dwParam &= ~0x0F;
382 	    dwParam |= mom->ChannelMap[chn]->aChn[chn];
383 
384 	    if ((LOBYTE(LOWORD(dwParam)) & 0xF0) == 0xC0 /* program change */ &&
385 		mom->ChannelMap[chn]->lpbPatch)
386 	    {
387 		BYTE patch = HIBYTE(LOWORD(dwParam));
388 
389 		/* change patch */
390 		dwParam &= ~0x0000FF00;
391 		dwParam |= mom->ChannelMap[chn]->lpbPatch[patch];
392 	    }
393 	    ret = midiOutShortMsg(mom->ChannelMap[chn]->hMidi, dwParam);
394 	}
395 	break;
396     case 0xF0:
397 	for (chn = 0; chn < 16; chn++)
398 	{
399 	    if (mom->ChannelMap[chn]->loaded > 0)
400 		ret = midiOutShortMsg(mom->ChannelMap[chn]->hMidi, dwParam);
401 	}
402 	break;
403     default:
404 	FIXME("ooch %lx\n", dwParam);
405     }
406 
407     return ret;
408 }
409 
modPrepare(MIDIMAPDATA * mom,LPMIDIHDR lpMidiHdr,DWORD_PTR dwParam2)410 static	DWORD	modPrepare(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD_PTR dwParam2)
411 {
412     if (MIDIMAP_IsBadData(mom)) return MMSYSERR_ERROR;
413     if (lpMidiHdr->dwFlags & (MHDR_ISSTRM|MHDR_PREPARED))
414 	return MMSYSERR_INVALPARAM;
415 
416     lpMidiHdr->dwFlags |= MHDR_PREPARED;
417     return MMSYSERR_NOERROR;
418 }
419 
modUnprepare(MIDIMAPDATA * mom,LPMIDIHDR lpMidiHdr,DWORD_PTR dwParam2)420 static	DWORD	modUnprepare(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD_PTR dwParam2)
421 {
422     if (MIDIMAP_IsBadData(mom)) return MMSYSERR_ERROR;
423     if ((lpMidiHdr->dwFlags & MHDR_ISSTRM) || !(lpMidiHdr->dwFlags & MHDR_PREPARED))
424 	return MMSYSERR_INVALPARAM;
425 
426     lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
427     return MMSYSERR_NOERROR;
428 }
429 
modGetDevCaps(UINT wDevID,MIDIMAPDATA * mom,LPMIDIOUTCAPSW lpMidiCaps,DWORD_PTR size)430 static	DWORD	modGetDevCaps(UINT wDevID, MIDIMAPDATA* mom, LPMIDIOUTCAPSW lpMidiCaps, DWORD_PTR size)
431 {
432     static const WCHAR name[] = {'W','i','n','e',' ','m','i','d','i',' ','m','a','p','p','e','r',0};
433     lpMidiCaps->wMid = 0x00FF;
434     lpMidiCaps->wPid = 0x0001;
435     lpMidiCaps->vDriverVersion = 0x0100;
436     lstrcpyW(lpMidiCaps->szPname, name);
437     lpMidiCaps->wTechnology = MOD_MAPPER;
438     lpMidiCaps->wVoices = 0;
439     lpMidiCaps->wNotes = 0;
440     lpMidiCaps->wChannelMask = 0xFFFF;
441     lpMidiCaps->dwSupport = 0L;
442 
443     return MMSYSERR_NOERROR;
444 }
445 
modReset(MIDIMAPDATA * mom)446 static	DWORD	modReset(MIDIMAPDATA* mom)
447 {
448     WORD	chn;
449     DWORD	ret = MMSYSERR_NOERROR;
450 
451     if (MIDIMAP_IsBadData(mom))
452 	return MMSYSERR_ERROR;
453 
454     for (chn = 0; chn < 16; chn++)
455     {
456 	if (mom->ChannelMap[chn] && mom->ChannelMap[chn]->loaded > 0)
457 	{
458 	    ret = midiOutReset(mom->ChannelMap[chn]->hMidi);
459 	    if (ret != MMSYSERR_NOERROR) break;
460 	}
461     }
462     return ret;
463 }
464 
465 /**************************************************************************
466  * 				modMessage (MIDIMAP.@)
467  */
MIDIMAP_modMessage(UINT wDevID,UINT wMsg,DWORD_PTR dwUser,DWORD_PTR dwParam1,DWORD_PTR dwParam2)468 DWORD WINAPI MIDIMAP_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
469 				DWORD_PTR dwParam1, DWORD_PTR dwParam2)
470 {
471     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
472 	  wDevID, wMsg, dwUser, dwParam1, dwParam2);
473 
474     switch (wMsg)
475     {
476     case DRVM_INIT:
477     case DRVM_EXIT:
478     case DRVM_ENABLE:
479     case DRVM_DISABLE:
480 	/* FIXME: Pretend this is supported */
481 	return 0;
482 
483     case MODM_OPEN: return modOpen((DWORD_PTR *)dwUser, (LPMIDIOPENDESC)dwParam1, dwParam2);
484     case MODM_CLOSE:	 	return modClose		((MIDIMAPDATA*)dwUser);
485 
486     case MODM_DATA:		return modData		((MIDIMAPDATA*)dwUser, dwParam1);
487     case MODM_LONGDATA:		return modLongData      ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1,     dwParam2);
488     case MODM_PREPARE:	 	return modPrepare	((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, 	dwParam2);
489     case MODM_UNPREPARE: 	return modUnprepare	((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, 	dwParam2);
490     case MODM_RESET:		return modReset		((MIDIMAPDATA*)dwUser);
491 
492     case MODM_GETDEVCAPS:	return modGetDevCaps	(wDevID, (MIDIMAPDATA*)dwUser, (LPMIDIOUTCAPSW)dwParam1,dwParam2);
493     case MODM_GETNUMDEVS:	return 1;
494     case MODM_GETVOLUME:	return MMSYSERR_NOTSUPPORTED;
495     case MODM_SETVOLUME:	return MMSYSERR_NOTSUPPORTED;
496     default:
497 	FIXME("unknown message %d!\n", wMsg);
498     }
499     return MMSYSERR_NOTSUPPORTED;
500 }
501 
502 /*======================================================================*
503  *                  Driver part                                         *
504  *======================================================================*/
505 
506 /**************************************************************************
507  * 				MIDIMAP_drvOpen			[internal]
508  */
MIDIMAP_drvOpen(LPSTR str)509 static	LRESULT	MIDIMAP_drvOpen(LPSTR str)
510 {
511     MIDIOUTCAPSW	moc;
512     unsigned		dev, i;
513 
514     if (midiOutPorts)
515 	return 0;
516 
517     numMidiOutPorts = midiOutGetNumDevs();
518     midiOutPorts = HeapAlloc(GetProcessHeap(), 0,
519 			     numMidiOutPorts * sizeof(MIDIOUTPORT));
520     for (dev = 0; dev < numMidiOutPorts; dev++)
521     {
522 	if (midiOutGetDevCapsW(dev, &moc, sizeof(moc)) == 0L)
523 	{
524 	    strcpyW(midiOutPorts[dev].name, moc.szPname);
525 	    midiOutPorts[dev].loaded = 0;
526 	    midiOutPorts[dev].hMidi = 0;
527 	    midiOutPorts[dev].uDevID = dev;
528 	    midiOutPorts[dev].lpbPatch = NULL;
529 	    for (i = 0; i < 16; i++)
530 		midiOutPorts[dev].aChn[i] = i;
531 	}
532 	else
533 	{
534 	    midiOutPorts[dev].loaded = -1;
535 	}
536     }
537 
538     return 1;
539 }
540 
541 /**************************************************************************
542  * 				MIDIMAP_drvClose		[internal]
543  */
MIDIMAP_drvClose(DWORD_PTR dwDevID)544 static	LRESULT	MIDIMAP_drvClose(DWORD_PTR dwDevID)
545 {
546     if (midiOutPorts)
547     {
548 	HeapFree(GetProcessHeap(), 0, midiOutPorts);
549 	midiOutPorts = NULL;
550 	return 1;
551     }
552     return 0;
553 }
554 
555 /**************************************************************************
556  * 				DriverProc (MIDIMAP.@)
557  */
MIDIMAP_DriverProc(DWORD_PTR dwDevID,HDRVR hDriv,UINT wMsg,LPARAM dwParam1,LPARAM dwParam2)558 LRESULT CALLBACK	MIDIMAP_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
559 				   LPARAM dwParam1, LPARAM dwParam2)
560 {
561 /* EPP     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",  */
562 /* EPP 	  dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
563 
564     switch (wMsg)
565     {
566     case DRV_LOAD:		return 1;
567     case DRV_FREE:		return 1;
568     case DRV_OPEN:		return MIDIMAP_drvOpen((LPSTR)dwParam1);
569     case DRV_CLOSE:		return MIDIMAP_drvClose(dwDevID);
570     case DRV_ENABLE:		return 1;
571     case DRV_DISABLE:		return 1;
572     case DRV_QUERYCONFIGURE:	return 1;
573     case DRV_CONFIGURE:		MessageBoxA(0, "MIDIMAP MultiMedia Driver !", "OSS Driver", MB_OK);	return 1;
574     case DRV_INSTALL:		return DRVCNF_RESTART;
575     case DRV_REMOVE:		return DRVCNF_RESTART;
576     default:
577 	return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
578     }
579 }
580