vkd3d: Disable printf format checks.
[wine.git] / dlls / winmm / lolvldrv.c
blobe664021dc6449579bbfc8d4480cda7c4e34e21a4
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MMSYSTEM low level drivers handling functions
6 * Copyright 1999 Eric Pouech
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define COBJMACROS
25 #include <string.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <assert.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winreg.h"
32 #include "winnls.h"
33 #include "winemm.h"
34 #include "wine/debug.h"
35 #include "wine/exception.h"
37 #include "wingdi.h"
38 #include "ole2.h"
39 #include "devpkey.h"
40 #include "mmdeviceapi.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(winmm);
44 /* each known type of driver has an instance of this structure */
45 typedef struct tagWINE_LLTYPE {
46 /* those attributes depend on the specification of the type */
47 LPCSTR typestr; /* name (for debugging) */
48 /* those attributes reflect the loaded/current situation for the type */
49 UINT wMaxId; /* number of loaded devices (sum across all loaded drivers) */
50 LPWINE_MLD lpMlds; /* "static" mlds to access the part though device IDs */
51 int nMapper; /* index to mapper */
52 } WINE_LLTYPE;
54 static WINE_LLTYPE llTypes[MMDRV_MAX] = {
55 { "Aux", 0, 0, -1 },
56 { "Mixer", 0, 0, -1 },
57 { "MidiIn", 0, 0, -1 },
58 { "MidiOut", 0, 0, -1 },
59 { "WaveIn", 0, 0, -1 },
60 { "WaveOut", 0, 0, -1 }
63 static BOOL drivers_loaded;
64 static int MMDrvsHi;
65 static WINE_MM_DRIVER MMDrvs[8];
66 static LPWINE_MLD MM_MLDrvs[40];
68 static void MMDRV_Init(void);
70 static void MMDRV_InitSingleType(UINT type) {
71 if (!drivers_loaded) {
72 drivers_loaded = TRUE;
73 MMDRV_Init();
77 /**************************************************************************
78 * MMDRV_GetNum [internal]
80 UINT MMDRV_GetNum(UINT type)
82 TRACE("(%04x)\n", type);
83 assert(type < MMDRV_MAX);
84 MMDRV_InitSingleType(type);
85 return llTypes[type].wMaxId;
88 /**************************************************************************
89 * MMDRV_Message [internal]
91 DWORD MMDRV_Message(LPWINE_MLD mld, UINT wMsg, DWORD_PTR dwParam1,
92 DWORD_PTR dwParam2)
94 LPWINE_MM_DRIVER lpDrv;
95 DWORD ret;
96 WINE_MM_DRIVER_PART* part;
97 WINE_LLTYPE* llType = &llTypes[mld->type];
99 TRACE("(%s %d %u 0x%08Ix 0x%08Ix 0x%08Ix)\n",
100 llTypes[mld->type].typestr, mld->uDeviceID, wMsg,
101 mld->dwDriverInstance, dwParam1, dwParam2);
103 if ((UINT16)mld->uDeviceID == (UINT16)-1) {
104 if (llType->nMapper == -1) {
105 WARN("uDev=-1 requested on non-mapped ll type %s\n",
106 llTypes[mld->type].typestr);
107 return MMSYSERR_BADDEVICEID;
109 } else {
110 if (mld->uDeviceID >= llType->wMaxId) {
111 WARN("uDev(%u) requested >= max (%d)\n", mld->uDeviceID, llType->wMaxId);
112 return MMSYSERR_BADDEVICEID;
116 lpDrv = &MMDrvs[mld->mmdIndex];
117 part = &lpDrv->parts[mld->type];
119 assert(part->fnMessage32);
121 TRACE("Calling message(dev=%d msg=%u usr=0x%08Ix p1=0x%08Ix p2=0x%08Ix)\n",
122 mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2);
123 ret = part->fnMessage32(mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2);
124 TRACE("=> %s\n", WINMM_ErrorToString(ret));
126 return ret;
129 /**************************************************************************
130 * MMDRV_Alloc [internal]
132 LPWINE_MLD MMDRV_Alloc(UINT size, UINT type, LPHANDLE hndl, DWORD* dwFlags,
133 DWORD_PTR* dwCallback, DWORD_PTR* dwInstance)
135 LPWINE_MLD mld;
136 UINT_PTR i;
137 TRACE("(%d, %04x, %p, %p, %p, %p)\n",
138 size, type, hndl, dwFlags, dwCallback, dwInstance);
140 mld = calloc(1, size);
141 if (!mld) return NULL;
143 /* find an empty slot in MM_MLDrvs table */
144 for (i = 0; i < ARRAY_SIZE(MM_MLDrvs); i++) if (!MM_MLDrvs[i]) break;
146 if (i == ARRAY_SIZE(MM_MLDrvs)) {
147 /* the MM_MLDrvs table could be made growable in the future if needed */
148 ERR("Too many open drivers\n");
149 free(mld);
150 return NULL;
152 MM_MLDrvs[i] = mld;
153 *hndl = (HANDLE)(i | 0x8000);
155 mld->type = type;
156 if ((UINT_PTR)*hndl < MMDRV_GetNum(type) || ((UINT_PTR)*hndl >> 16)) {
157 /* FIXME: those conditions must be fulfilled so that:
158 * - we can distinguish between device IDs and handles
159 * - we can use handles as 16 or 32 bit entities
161 ERR("Shouldn't happen. Bad allocation scheme\n");
164 mld->dwFlags = HIWORD(*dwFlags);
165 mld->dwCallback = *dwCallback;
166 mld->dwClientInstance = *dwInstance;
168 return mld;
171 /**************************************************************************
172 * MMDRV_Free [internal]
174 void MMDRV_Free(HANDLE hndl, LPWINE_MLD mld)
176 TRACE("(%p, %p)\n", hndl, mld);
178 if ((UINT_PTR)hndl & 0x8000) {
179 UINT_PTR idx = (UINT_PTR)hndl & ~0x8000;
180 if (idx < ARRAY_SIZE(MM_MLDrvs)) {
181 MM_MLDrvs[idx] = NULL;
182 free(mld);
183 return;
186 ERR("Bad Handle %p at %p (not freed)\n", hndl, mld);
189 /**************************************************************************
190 * MMDRV_Open [internal]
192 DWORD MMDRV_Open(LPWINE_MLD mld, UINT wMsg, DWORD_PTR dwParam1, DWORD dwFlags)
194 DWORD dwRet = MMSYSERR_BADDEVICEID;
195 DWORD_PTR dwInstance;
196 WINE_LLTYPE* llType = &llTypes[mld->type];
197 TRACE("(%p, %04x, 0x%08Ix, 0x%08lx)\n", mld, wMsg, dwParam1, dwFlags);
199 mld->dwDriverInstance = (DWORD_PTR)&dwInstance;
201 if (mld->uDeviceID == (UINT)-1 || mld->uDeviceID == (UINT16)-1) {
202 TRACE("MAPPER mode requested !\n");
203 if (llType->nMapper == -1) {
204 WARN("Mapper not supported for type %s\n", llTypes[mld->type].typestr);
205 return MMSYSERR_BADDEVICEID;
207 mld->mmdIndex = llType->lpMlds[-1].mmdIndex;
208 TRACE("Setting mmdIndex to %u\n", mld->mmdIndex);
209 dwRet = MMDRV_Message(mld, wMsg, dwParam1, dwFlags);
210 } else {
211 if (mld->uDeviceID < llType->wMaxId) {
212 mld->mmdIndex = llType->lpMlds[mld->uDeviceID].mmdIndex;
213 TRACE("Setting mmdIndex to %u\n", mld->mmdIndex);
214 dwRet = MMDRV_Message(mld, wMsg, dwParam1, dwFlags);
217 if (dwRet == MMSYSERR_NOERROR)
218 mld->dwDriverInstance = dwInstance;
219 return dwRet;
222 /**************************************************************************
223 * MMDRV_Close [internal]
225 DWORD MMDRV_Close(LPWINE_MLD mld, UINT wMsg)
227 TRACE("(%p, %04x)\n", mld, wMsg);
228 return MMDRV_Message(mld, wMsg, 0L, 0L);
231 /**************************************************************************
232 * MMDRV_GetByID [internal]
234 static LPWINE_MLD MMDRV_GetByID(UINT uDevID, UINT type)
236 TRACE("(%04x, %04x)\n", uDevID, type);
237 if (uDevID < llTypes[type].wMaxId)
238 return &llTypes[type].lpMlds[uDevID];
239 if ((uDevID == (UINT16)-1 || uDevID == (UINT)-1) && llTypes[type].nMapper != -1)
240 return &llTypes[type].lpMlds[-1];
241 return NULL;
244 /**************************************************************************
245 * MMDRV_Get [internal]
247 LPWINE_MLD MMDRV_Get(HANDLE _hndl, UINT type, BOOL bCanBeID)
249 LPWINE_MLD mld = NULL;
250 UINT_PTR hndl = (UINT_PTR)_hndl;
251 TRACE("(%p, %04x, %c)\n", _hndl, type, bCanBeID ? 'Y' : 'N');
253 assert(type < MMDRV_MAX);
254 MMDRV_InitSingleType(type);
256 if (hndl >= llTypes[type].wMaxId &&
257 hndl != (UINT16)-1 && hndl != (UINT)-1) {
258 if (hndl & 0x8000) {
259 UINT idx = hndl & ~0x8000;
260 if (idx < ARRAY_SIZE(MM_MLDrvs)) {
261 __TRY
263 mld = MM_MLDrvs[idx];
264 if (mld && mld->type != type) mld = NULL;
266 __EXCEPT_PAGE_FAULT
268 mld = NULL;
270 __ENDTRY;
274 if (mld == NULL && bCanBeID) {
275 mld = MMDRV_GetByID(hndl, type);
277 return mld;
280 /**************************************************************************
281 * MMDRV_PhysicalFeatures [internal]
283 UINT MMDRV_PhysicalFeatures(LPWINE_MLD mld, UINT uMsg,
284 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
286 WINE_MM_DRIVER* lpDrv = &MMDrvs[mld->mmdIndex];
288 TRACE("(%p, %04x, %08Ix, %08Ix)\n", mld, uMsg, dwParam1, dwParam2);
290 /* all those function calls are undocumented */
291 switch (uMsg) {
292 case DRV_QUERYDRVENTRY:
293 lstrcpynA((LPSTR)dwParam1, lpDrv->drvname, LOWORD(dwParam2));
294 break;
295 case DRV_QUERYDEVNODE:
296 *(LPDWORD)dwParam1 = 0L; /* should be DevNode */
297 break;
298 case DRV_QUERYNAME:
299 WARN("NIY QueryName\n");
300 break;
301 case DRV_QUERYDRIVERIDS:
302 WARN("NIY call VxD\n");
303 /* should call VxD MMDEVLDR with (DevNode, dwParam1 and dwParam2) as pmts
304 * dwParam1 is buffer and dwParam2 is sizeof(buffer)
305 * I don't know where the result is stored though
307 break;
308 case DRV_QUERYMAPPABLE:
309 return (lpDrv->bIsMapper) ? 2 : 0;
311 case DRVM_MAPPER_PREFERRED_GET:
312 /* FIXME: get from registry someday */
313 *((LPDWORD)dwParam1) = -1; /* No preferred device */
314 *((LPDWORD)dwParam2) = 0;
315 break;
317 case DRV_QUERYDEVICEINTERFACE:
318 case DRV_QUERYDEVICEINTERFACESIZE:
319 return MMDRV_Message(mld, uMsg, dwParam1, dwParam2);
321 default:
322 WARN("Unknown call %04x\n", uMsg);
323 return MMSYSERR_INVALPARAM;
325 return 0L;
328 /**************************************************************************
329 * MMDRV_InitPerType [internal]
331 static BOOL MMDRV_InitPerType(LPWINE_MM_DRIVER lpDrv, UINT type, UINT wMsg)
333 WINE_MM_DRIVER_PART* part = &lpDrv->parts[type];
334 DWORD ret;
335 UINT count = 0;
336 int i, k;
337 WINE_MLD *mem;
339 TRACE("(%p, %04x, %04x)\n", lpDrv, type, wMsg);
341 part->nIDMin = part->nIDMax = 0;
343 /* for DRVM_INIT and DRVM_ENABLE, dwParam2 should be PnP node */
344 /* the DRVM_ENABLE is only required when the PnP node is non zero */
345 if (part->fnMessage32) {
346 ret = part->fnMessage32(0, DRVM_INIT, 0L, 0L, 0L);
347 TRACE("DRVM_INIT => %s\n", WINMM_ErrorToString(ret));
348 #if 0
349 ret = part->fnMessage32(0, DRVM_ENABLE, 0L, 0L, 0L);
350 TRACE("DRVM_ENABLE => %08lx\n", ret);
351 #endif
352 count = part->fnMessage32(0, wMsg, 0L, 0L, 0L);
354 else return FALSE;
356 TRACE("Got %u dev for (%s:%s)\n", count, lpDrv->drvname, llTypes[type].typestr);
358 if (HIWORD(count))
359 return FALSE;
361 /* got some drivers */
362 if (lpDrv->bIsMapper) {
363 llTypes[type].nMapper = MMDrvsHi;
364 } else {
365 if (count == 0)
366 return FALSE;
367 part->nIDMin = llTypes[type].wMaxId;
368 llTypes[type].wMaxId += count;
369 part->nIDMax = llTypes[type].wMaxId;
371 TRACE("Setting min=%d max=%d (ttop=%d) for (%s:%s)\n",
372 part->nIDMin, part->nIDMax, llTypes[type].wMaxId,
373 lpDrv->drvname, llTypes[type].typestr);
374 /* realloc translation table */
375 mem = llTypes[type].lpMlds ? llTypes[type].lpMlds - 1 : NULL;
376 mem = realloc(mem, sizeof(WINE_MLD) * (llTypes[type].wMaxId + 1));
377 llTypes[type].lpMlds = mem + 1;
379 /* re-build the translation table */
380 if (lpDrv->bIsMapper) {
381 TRACE("%s:Trans[%d] -> %s\n", llTypes[type].typestr, -1, MMDrvs[llTypes[type].nMapper].drvname);
382 llTypes[type].lpMlds[-1].uDeviceID = (UINT)-1;
383 llTypes[type].lpMlds[-1].type = type;
384 llTypes[type].lpMlds[-1].mmdIndex = llTypes[type].nMapper;
385 llTypes[type].lpMlds[-1].dwDriverInstance = 0;
387 for (i = k = 0; i <= MMDrvsHi; i++) {
388 while (MMDrvs[i].parts[type].nIDMin <= k && k < MMDrvs[i].parts[type].nIDMax) {
389 TRACE("%s:Trans[%d] -> %s\n", llTypes[type].typestr, k, MMDrvs[i].drvname);
390 llTypes[type].lpMlds[k].uDeviceID = k;
391 llTypes[type].lpMlds[k].type = type;
392 llTypes[type].lpMlds[k].mmdIndex = i;
393 llTypes[type].lpMlds[k].dwDriverInstance = 0;
394 k++;
397 return TRUE;
400 /**************************************************************************
401 * MMDRV_Install [internal]
403 static BOOL MMDRV_Install(LPCSTR drvRegName, LPCSTR drvFileName, BOOL bIsMapper)
405 int i, count = 0;
406 LPWINE_MM_DRIVER lpDrv = &MMDrvs[MMDrvsHi];
407 LPWINE_DRIVER d;
408 WINEMM_msgFunc32 func;
410 TRACE("('%s', '%s', mapper=%c);\n", drvRegName, drvFileName, bIsMapper ? 'Y' : 'N');
412 for (i = 0; i < MMDrvsHi; i++) {
413 if (!strcmp(drvRegName, MMDrvs[i].drvname)) return FALSE;
416 /* Be sure that size of MMDrvs matches the max number of loadable
417 * drivers !!
418 * If not just increase size of MMDrvs
420 assert(MMDrvsHi <= ARRAY_SIZE(MMDrvs));
422 memset(lpDrv, 0, sizeof(*lpDrv));
424 if (!(lpDrv->hDriver = OpenDriverA(drvFileName, 0, 0))) {
425 WARN("Couldn't open driver '%s'\n", drvFileName);
426 return FALSE;
429 d = DRIVER_FindFromHDrvr(lpDrv->hDriver);
431 /* Then look for xxxMessage functions */
432 #define AA(_h,_w,_x,_y,_z) \
433 func = (WINEMM_msgFunc##_y) _z ((_h), #_x); \
434 if (func != NULL) \
435 { lpDrv->parts[_w].fnMessage##_y = func; count++; \
436 TRACE("Got %d bit func '%s'\n", _y, #_x); }
438 if (d->hModule) {
439 #define A(_x,_y) AA(d->hModule,_x,_y,32,GetProcAddress)
440 A(MMDRV_AUX, auxMessage);
441 A(MMDRV_MIXER, mxdMessage);
442 A(MMDRV_MIDIIN, midMessage);
443 A(MMDRV_MIDIOUT, modMessage);
444 A(MMDRV_WAVEIN, widMessage);
445 A(MMDRV_WAVEOUT, wodMessage);
446 #undef A
448 #undef AA
450 if (!count) {
451 CloseDriver(lpDrv->hDriver, 0, 0);
452 WARN("No message functions found\n");
453 return FALSE;
456 /* FIXME: being a mapper or not should be known by another way */
457 /* it's known for NE drvs (the description is of the form '*mapper: *'
458 * I don't have any clue for PE drvs
460 lpDrv->bIsMapper = bIsMapper;
461 lpDrv->drvname = strdup(drvRegName);
463 /* Finish init and get the count of the devices */
464 i = 0;
465 if (MMDRV_InitPerType(lpDrv, MMDRV_AUX, AUXDM_GETNUMDEVS)) i = 1;
466 if (MMDRV_InitPerType(lpDrv, MMDRV_MIXER, MXDM_GETNUMDEVS)) i = 1;
467 if (MMDRV_InitPerType(lpDrv, MMDRV_MIDIIN, MIDM_GETNUMDEVS)) i = 1;
468 if (MMDRV_InitPerType(lpDrv, MMDRV_MIDIOUT, MODM_GETNUMDEVS)) i = 1;
469 if (MMDRV_InitPerType(lpDrv, MMDRV_WAVEIN, WIDM_GETNUMDEVS)) i = 1;
470 if (MMDRV_InitPerType(lpDrv, MMDRV_WAVEOUT, WODM_GETNUMDEVS)) i = 1;
471 /* if all those func calls return FALSE, then the driver must be unloaded */
472 if (!i) {
473 CloseDriver(lpDrv->hDriver, 0, 0);
474 free(lpDrv->drvname);
475 WARN("Driver initialization failed\n");
476 return FALSE;
479 MMDrvsHi++;
481 return TRUE;
484 /**************************************************************************
485 * MMDRV_Init
487 static void MMDRV_Init(void)
489 IMMDeviceEnumerator *devenum;
490 IMMDevice *device;
491 IPropertyStore *ps;
492 PROPVARIANT pv;
493 DWORD size;
494 char *drvA;
495 HRESULT init_hr, hr;
497 TRACE("()\n");
499 init_hr = CoInitialize(NULL);
501 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL,
502 CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&devenum);
503 if(FAILED(hr)){
504 ERR("CoCreateInstance failed: %08lx\n", hr);
505 goto exit;
508 hr = IMMDeviceEnumerator_GetDevice(devenum, L"Wine info device", &device);
509 IMMDeviceEnumerator_Release(devenum);
510 if(FAILED(hr)){
511 ERR("GetDevice failed: %08lx\n", hr);
512 goto exit;
515 hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
516 if(FAILED(hr)){
517 ERR("OpenPropertyStore failed: %08lx\n", hr);
518 IMMDevice_Release(device);
519 goto exit;
522 hr = IPropertyStore_GetValue(ps,
523 (const PROPERTYKEY *)&DEVPKEY_Device_Driver, &pv);
524 IPropertyStore_Release(ps);
525 IMMDevice_Release(device);
526 if(FAILED(hr)){
527 ERR("GetValue failed: %08lx\n", hr);
528 goto exit;
531 size = WideCharToMultiByte(CP_ACP, 0, pv.pwszVal, -1,
532 NULL, 0, NULL, NULL);
533 drvA = malloc(size);
534 WideCharToMultiByte(CP_ACP, 0, pv.pwszVal, -1, drvA, size, NULL, NULL);
536 MMDRV_Install(drvA, drvA, FALSE);
538 free(drvA);
539 PropVariantClear(&pv);
541 MMDRV_Install("wavemapper", "msacm32.drv", TRUE);
542 MMDRV_Install("midimapper", "midimap.dll", TRUE);
544 exit:
545 if(SUCCEEDED(init_hr))
546 CoUninitialize();
549 /******************************************************************
550 * ExitPerType
554 static BOOL MMDRV_ExitPerType(LPWINE_MM_DRIVER lpDrv, UINT type)
556 WINE_MM_DRIVER_PART* part = &lpDrv->parts[type];
557 DWORD ret;
558 TRACE("(%p, %04x)\n", lpDrv, type);
560 if (part->fnMessage32) {
561 #if 0
562 ret = part->fnMessage32(0, DRVM_DISABLE, 0L, 0L, 0L);
563 TRACE("DRVM_DISABLE => %08lx\n", ret);
564 #endif
565 ret = part->fnMessage32(0, DRVM_EXIT, 0L, 0L, 0L);
566 TRACE("DRVM_EXIT => %s\n", WINMM_ErrorToString(ret));
569 return TRUE;
572 /******************************************************************
573 * Exit
577 void MMDRV_Exit(void)
579 unsigned int i;
580 TRACE("()\n");
582 for (i = 0; i < ARRAY_SIZE(MM_MLDrvs); i++)
584 if (MM_MLDrvs[i] != NULL)
586 FIXME("Closing while ll-driver open\n");
587 #if 0
588 /* FIXME: should generate a message depending on type */
589 MMDRV_Free((HANDLE)(i | 0x8000), MM_MLDrvs[i]);
590 #endif
594 /* unload driver, in reverse order of loading */
595 i = ARRAY_SIZE(MMDrvs);
596 while (i-- > 0)
598 MMDRV_ExitPerType(&MMDrvs[i], MMDRV_AUX);
599 MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIXER);
600 MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIDIIN);
601 MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIDIOUT);
602 MMDRV_ExitPerType(&MMDrvs[i], MMDRV_WAVEIN);
603 MMDRV_ExitPerType(&MMDrvs[i], MMDRV_WAVEOUT);
604 CloseDriver(MMDrvs[i].hDriver, 0, 0);
606 if (llTypes[MMDRV_AUX].lpMlds)
607 free(llTypes[MMDRV_AUX].lpMlds - 1);
608 if (llTypes[MMDRV_MIXER].lpMlds)
609 free(llTypes[MMDRV_MIXER].lpMlds - 1);
610 if (llTypes[MMDRV_MIDIIN].lpMlds)
611 free(llTypes[MMDRV_MIDIIN].lpMlds - 1);
612 if (llTypes[MMDRV_MIDIOUT].lpMlds)
613 free(llTypes[MMDRV_MIDIOUT].lpMlds - 1);
614 if (llTypes[MMDRV_WAVEIN].lpMlds)
615 free(llTypes[MMDRV_WAVEIN].lpMlds - 1);
616 if (llTypes[MMDRV_WAVEOUT].lpMlds)
617 free(llTypes[MMDRV_WAVEOUT].lpMlds - 1);