ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

winmm.c
Go to the documentation of this file.
00001 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
00002 
00003 /*
00004  * WINMM functions
00005  *
00006  * Copyright 1993      Martin Ayotte
00007  *           1998-2002 Eric Pouech
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00022  */
00023 
00024 /*
00025  * Eric POUECH :
00026  *  98/9    added Win32 MCI support
00027  *      99/4    added midiStream support
00028  *      99/9    added support for loadable low level drivers
00029  */
00030 
00031 /* TODO
00032  *      + it seems that some programs check what's installed in
00033  *        registry against the value returned by drivers. Wine is
00034  *        currently broken regarding this point.
00035  *      + check thread-safeness for MMSYSTEM and WINMM entry points
00036  *      + unicode entry points are badly supported (would require
00037  *        moving 32 bit drivers as Unicode as they are supposed to be)
00038  *      + allow joystick and timer external calls as we do for wave,
00039  *        midi, mixer and aux
00040  */
00041 
00042 #include <stdio.h>
00043 #include <stdarg.h>
00044 #include <string.h>
00045 
00046 #define NONAMELESSUNION
00047 #define NONAMELESSSTRUCT
00048 #include "windef.h"
00049 #include "winbase.h"
00050 #include "mmsystem.h"
00051 #include "winuser.h"
00052 #include "winnls.h"
00053 #include "winternl.h"
00054 #include "winemm.h"
00055 
00056 #include "wine/debug.h"
00057 
00058 WINE_DEFAULT_DEBUG_CHANNEL(winmm);
00059 
00060 /* ========================================================================
00061  *                   G L O B A L   S E T T I N G S
00062  * ========================================================================*/
00063 
00064 HINSTANCE hWinMM32Instance;
00065 HANDLE psLastEvent;
00066 HANDLE psStopEvent;
00067 
00068 CRITICAL_SECTION WINMM_cs;
00069 
00070 /**************************************************************************
00071  *          WINMM_CreateIData           [internal]
00072  */
00073 static  BOOL    WINMM_CreateIData(HINSTANCE hInstDLL)
00074 {
00075     hWinMM32Instance = hInstDLL;
00076     psStopEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
00077     psLastEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
00078     InitializeCriticalSection(&WINMM_cs);
00079     return TRUE;
00080 }
00081 
00082 /**************************************************************************
00083  *          WINMM_DeleteIData           [internal]
00084  */
00085 static  void WINMM_DeleteIData(void)
00086 {
00087     TIME_MMTimeStop();
00088 
00089     /* FIXME: should also free content and resources allocated
00090      * inside WINMM_IData */
00091     CloseHandle(psStopEvent);
00092     CloseHandle(psLastEvent);
00093     DeleteCriticalSection(&WINMM_cs);
00094 }
00095 
00096 /******************************************************************
00097  *             WINMM_LoadMMSystem
00098  *
00099  */
00100 static HANDLE (WINAPI *pGetModuleHandle16)(LPCSTR);
00101 static DWORD (WINAPI *pLoadLibrary16)(LPCSTR);
00102 
00103 BOOL WINMM_CheckForMMSystem(void)
00104 {
00105     /* 0 is not checked yet, -1 is not present, 1 is present */
00106     static      int    loaded /* = 0 */;
00107 
00108     if (loaded == 0)
00109     {
00110         HANDLE      h = GetModuleHandleA("kernel32");
00111         loaded = -1;
00112         if (h)
00113         {
00114             pGetModuleHandle16 = (void*)GetProcAddress(h, "GetModuleHandle16");
00115             pLoadLibrary16 = (void*)GetProcAddress(h, (LPCSTR)35); /* ordinal for LoadLibrary16 */
00116             if (pGetModuleHandle16 && pLoadLibrary16 &&
00117                 (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL")))
00118                 loaded = 1;
00119         }
00120     }
00121     return loaded > 0;
00122 }
00123 
00124 /******************************************************************
00125  *             WINMM_ErrorToString
00126  */
00127 const char* WINMM_ErrorToString(MMRESULT error)
00128 {
00129 #define ERR_TO_STR(dev) case dev: return #dev
00130     static char unknown[32];
00131     switch (error) {
00132     ERR_TO_STR(MMSYSERR_NOERROR);
00133     ERR_TO_STR(MMSYSERR_ERROR);
00134     ERR_TO_STR(MMSYSERR_BADDEVICEID);
00135     ERR_TO_STR(MMSYSERR_NOTENABLED);
00136     ERR_TO_STR(MMSYSERR_ALLOCATED);
00137     ERR_TO_STR(MMSYSERR_INVALHANDLE);
00138     ERR_TO_STR(MMSYSERR_NODRIVER);
00139     ERR_TO_STR(MMSYSERR_NOMEM);
00140     ERR_TO_STR(MMSYSERR_NOTSUPPORTED);
00141     ERR_TO_STR(MMSYSERR_BADERRNUM);
00142     ERR_TO_STR(MMSYSERR_INVALFLAG);
00143     ERR_TO_STR(MMSYSERR_INVALPARAM);
00144     ERR_TO_STR(MMSYSERR_HANDLEBUSY);
00145     ERR_TO_STR(MMSYSERR_INVALIDALIAS);
00146     ERR_TO_STR(MMSYSERR_BADDB);
00147     ERR_TO_STR(MMSYSERR_KEYNOTFOUND);
00148     ERR_TO_STR(MMSYSERR_READERROR);
00149     ERR_TO_STR(MMSYSERR_WRITEERROR);
00150     ERR_TO_STR(MMSYSERR_DELETEERROR);
00151     ERR_TO_STR(MMSYSERR_VALNOTFOUND);
00152     ERR_TO_STR(MMSYSERR_NODRIVERCB);
00153     ERR_TO_STR(WAVERR_BADFORMAT);
00154     ERR_TO_STR(WAVERR_STILLPLAYING);
00155     ERR_TO_STR(WAVERR_UNPREPARED);
00156     ERR_TO_STR(WAVERR_SYNC);
00157     }
00158     sprintf(unknown, "Unknown(0x%08x)", error);
00159     return unknown;
00160 #undef ERR_TO_STR
00161 }
00162 
00163 /**************************************************************************
00164  *      DllMain (WINMM.init)
00165  *
00166  * WINMM DLL entry point
00167  *
00168  */
00169 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
00170 {
00171     TRACE("%p 0x%x %p\n", hInstDLL, fdwReason, fImpLoad);
00172 
00173     switch (fdwReason) {
00174     case DLL_PROCESS_ATTACH:
00175         DisableThreadLibraryCalls(hInstDLL);
00176 
00177     if (!WINMM_CreateIData(hInstDLL))
00178         return FALSE;
00179         if (!MMDRV_Init()) {
00180             WINMM_DeleteIData();
00181             return FALSE;
00182     }
00183     break;
00184     case DLL_PROCESS_DETACH:
00185         /* close all opened MCI drivers */
00186         MCI_SendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0L);
00187         MMDRV_Exit();
00188         /* There's no guarantee the drivers haven't already been unloaded on
00189          * process shutdown.
00190          */
00191         if (!fImpLoad)
00192         {
00193             /* now unload all remaining drivers... */
00194             DRIVER_UnloadAll();
00195         }
00196 
00197     WINMM_DeleteIData();
00198     break;
00199     }
00200     return TRUE;
00201 }
00202 
00203 /**************************************************************************
00204  *  Mixer devices. New to Win95
00205  */
00206 
00207 /**************************************************************************
00208  * find out the real mixer ID depending on hmix (depends on dwFlags)
00209  */
00210 static UINT MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags, LPWINE_MIXER * lplpwm)
00211 {
00212     LPWINE_MIXER    lpwm = NULL;
00213     UINT        uRet = MMSYSERR_NOERROR;
00214 
00215     switch (dwFlags & 0xF0000000ul) {
00216     case MIXER_OBJECTF_MIXER:
00217     lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
00218     break;
00219     case MIXER_OBJECTF_HMIXER:
00220     lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
00221     break;
00222     case MIXER_OBJECTF_WAVEOUT:
00223     lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE,  MMDRV_MIXER);
00224     break;
00225     case MIXER_OBJECTF_HWAVEOUT:
00226     lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
00227     break;
00228     case MIXER_OBJECTF_WAVEIN:
00229     lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN,  TRUE,  MMDRV_MIXER);
00230     break;
00231     case MIXER_OBJECTF_HWAVEIN:
00232     lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN,  FALSE, MMDRV_MIXER);
00233     break;
00234     case MIXER_OBJECTF_MIDIOUT:
00235     lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE,  MMDRV_MIXER);
00236     break;
00237     case MIXER_OBJECTF_HMIDIOUT:
00238     lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
00239     break;
00240     case MIXER_OBJECTF_MIDIIN:
00241     lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN,  TRUE,  MMDRV_MIXER);
00242     break;
00243     case MIXER_OBJECTF_HMIDIIN:
00244     lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN,  FALSE, MMDRV_MIXER);
00245     break;
00246     case MIXER_OBJECTF_AUX:
00247     lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX,     TRUE,  MMDRV_MIXER);
00248     break;
00249     default:
00250     WARN("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
00251         lpwm = 0;
00252         uRet = MMSYSERR_INVALFLAG;
00253     break;
00254     }
00255     *lplpwm = lpwm;
00256     if (lpwm == 0 && uRet == MMSYSERR_NOERROR)
00257         uRet = MMSYSERR_INVALPARAM;
00258     return uRet;
00259 }
00260 
00261 /**************************************************************************
00262  *              mixerGetNumDevs         [WINMM.@]
00263  */
00264 UINT WINAPI mixerGetNumDevs(void)
00265 {
00266     return MMDRV_GetNum(MMDRV_MIXER);
00267 }
00268 
00269 /**************************************************************************
00270  *              mixerGetDevCapsA        [WINMM.@]
00271  */
00272 UINT WINAPI mixerGetDevCapsA(UINT_PTR uDeviceID, LPMIXERCAPSA lpCaps, UINT uSize)
00273 {
00274     MIXERCAPSW micW;
00275     UINT       ret;
00276 
00277     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
00278 
00279     ret = mixerGetDevCapsW(uDeviceID, &micW, sizeof(micW));
00280 
00281     if (ret == MMSYSERR_NOERROR) {
00282         MIXERCAPSA micA;
00283         micA.wMid           = micW.wMid;
00284         micA.wPid           = micW.wPid;
00285         micA.vDriverVersion = micW.vDriverVersion;
00286         WideCharToMultiByte( CP_ACP, 0, micW.szPname, -1, micA.szPname,
00287                              sizeof(micA.szPname), NULL, NULL );
00288         micA.fdwSupport     = micW.fdwSupport;
00289         micA.cDestinations  = micW.cDestinations;
00290         memcpy(lpCaps, &micA, min(uSize, sizeof(micA)));
00291     }
00292     return ret;
00293 }
00294 
00295 /**************************************************************************
00296  *              mixerGetDevCapsW        [WINMM.@]
00297  */
00298 UINT WINAPI mixerGetDevCapsW(UINT_PTR uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize)
00299 {
00300     LPWINE_MLD wmld;
00301 
00302     if (lpCaps == NULL)        return MMSYSERR_INVALPARAM;
00303 
00304     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIXER, TRUE)) == NULL)
00305         return MMSYSERR_BADDEVICEID;
00306 
00307     return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize);
00308 }
00309 
00310 static void CALLBACK MIXER_WCallback(HMIXEROBJ hmx, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam, DWORD_PTR param2)
00311 {
00312     HWND hWnd = (HWND)dwInstance;
00313 
00314     if (!dwInstance)
00315         return;
00316 
00317     PostMessageW(hWnd, uMsg, (WPARAM)hmx, (LPARAM)dwParam);
00318 }
00319 
00320 /**************************************************************************
00321  *              mixerOpen           [WINMM.@]
00322  */
00323 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
00324                       DWORD_PTR dwInstance, DWORD fdwOpen)
00325 {
00326     HANDLE      hMix;
00327     LPWINE_MLD      wmld;
00328     DWORD       dwRet = 0;
00329     MIXEROPENDESC   mod;
00330 
00331     TRACE("(%p, %d, %08lx, %08lx, %08x)\n",
00332       lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
00333 
00334     mod.dwCallback = (DWORD_PTR)MIXER_WCallback;
00335     mod.dwInstance = 0;
00336 
00337 /* If callback is a function,
00338  * dwCallback contains function pointer
00339  * dwInstance private data
00340  *
00341  * if callback is a window
00342  * dwCallback contains a window handle
00343  */
00344     switch (fdwOpen & CALLBACK_TYPEMASK) {
00345     default:
00346         return MMSYSERR_INVALFLAG;
00347 
00348     case CALLBACK_NULL:
00349         break;
00350 
00351     case CALLBACK_WINDOW:
00352         mod.dwInstance = dwCallback;
00353         if (dwCallback && !IsWindow((HWND)dwCallback))
00354             return MMSYSERR_INVALPARAM;
00355         break;
00356     }
00357 
00358     wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
00359                &dwCallback, &dwInstance);
00360     wmld->uDeviceID = uDeviceID;
00361     mod.hmx = hMix;
00362 
00363     dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD_PTR)&mod, CALLBACK_FUNCTION);
00364 
00365     if (dwRet != MMSYSERR_NOERROR) {
00366     MMDRV_Free(hMix, wmld);
00367     hMix = 0;
00368     }
00369     if (lphMix) *lphMix = hMix;
00370     TRACE("=> %d hMixer=%p\n", dwRet, hMix);
00371 
00372     return dwRet;
00373 }
00374 
00375 /**************************************************************************
00376  *              mixerClose          [WINMM.@]
00377  */
00378 UINT WINAPI mixerClose(HMIXER hMix)
00379 {
00380     LPWINE_MLD      wmld;
00381     DWORD       dwRet;
00382 
00383     TRACE("(%p)\n", hMix);
00384 
00385     if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
00386 
00387     dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
00388     MMDRV_Free(hMix, wmld);
00389 
00390     return dwRet;
00391 }
00392 
00393 /**************************************************************************
00394  *              mixerGetID          [WINMM.@]
00395  */
00396 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
00397 {
00398     LPWINE_MIXER    lpwm;
00399     UINT        uRet = MMSYSERR_NOERROR;
00400 
00401     TRACE("(%p %p %08x)\n", hmix, lpid, fdwID);
00402 
00403     if ((uRet = MIXER_GetDev(hmix, fdwID, &lpwm)) != MMSYSERR_NOERROR)
00404     return uRet;
00405 
00406     if (lpid)
00407       *lpid = lpwm->mld.uDeviceID;
00408 
00409     return uRet;
00410 }
00411 
00412 /**************************************************************************
00413  *              mixerGetControlDetailsW     [WINMM.@]
00414  */
00415 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdW,
00416                     DWORD fdwDetails)
00417 {
00418     LPWINE_MIXER    lpwm;
00419     UINT        uRet = MMSYSERR_NOERROR;
00420 
00421     TRACE("(%p, %p, %08x)\n", hmix, lpmcdW, fdwDetails);
00422 
00423     if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR)
00424     return uRet;
00425 
00426     if (lpmcdW == NULL || lpmcdW->cbStruct != sizeof(*lpmcdW))
00427     return MMSYSERR_INVALPARAM;
00428 
00429     return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD_PTR)lpmcdW,
00430              fdwDetails);
00431 }
00432 
00433 /**************************************************************************
00434  *              mixerGetControlDetailsA [WINMM.@]
00435  */
00436 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
00437                                     DWORD fdwDetails)
00438 {
00439     DWORD           ret = MMSYSERR_NOTENABLED;
00440 
00441     TRACE("(%p, %p, %08x)\n", hmix, lpmcdA, fdwDetails);
00442 
00443     if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
00444     return MMSYSERR_INVALPARAM;
00445 
00446     switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
00447     case MIXER_GETCONTROLDETAILSF_VALUE:
00448     /* can safely use A structure as it is, no string inside */
00449     ret = mixerGetControlDetailsW(hmix, lpmcdA, fdwDetails);
00450     break;
00451     case MIXER_GETCONTROLDETAILSF_LISTTEXT:
00452     {
00453             MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA = lpmcdA->paDetails;
00454             MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW;
00455         int size = max(1, lpmcdA->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
00456             unsigned int i;
00457 
00458         if (lpmcdA->u.cMultipleItems != 0) {
00459         size *= lpmcdA->u.cMultipleItems;
00460         }
00461         pDetailsW = HeapAlloc(GetProcessHeap(), 0, size);
00462             lpmcdA->paDetails = pDetailsW;
00463             lpmcdA->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
00464         /* set up lpmcd->paDetails */
00465         ret = mixerGetControlDetailsW(hmix, lpmcdA, fdwDetails);
00466         /* copy from lpmcd->paDetails back to paDetailsW; */
00467             if (ret == MMSYSERR_NOERROR) {
00468                 for (i = 0; i < lpmcdA->u.cMultipleItems * lpmcdA->cChannels; i++) {
00469                     pDetailsA->dwParam1 = pDetailsW->dwParam1;
00470                     pDetailsA->dwParam2 = pDetailsW->dwParam2;
00471                     WideCharToMultiByte( CP_ACP, 0, pDetailsW->szName, -1,
00472                                          pDetailsA->szName,
00473                                          sizeof(pDetailsA->szName), NULL, NULL );
00474                     pDetailsA++;
00475                     pDetailsW++;
00476                 }
00477                 pDetailsA -= lpmcdA->u.cMultipleItems * lpmcdA->cChannels;
00478                 pDetailsW -= lpmcdA->u.cMultipleItems * lpmcdA->cChannels;
00479             }
00480         HeapFree(GetProcessHeap(), 0, pDetailsW);
00481         lpmcdA->paDetails = pDetailsA;
00482             lpmcdA->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
00483     }
00484     break;
00485     default:
00486     ERR("Unsupported fdwDetails=0x%08x\n", fdwDetails);
00487     }
00488 
00489     return ret;
00490 }
00491 
00492 /**************************************************************************
00493  *              mixerGetLineControlsA   [WINMM.@]
00494  */
00495 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
00496                   DWORD fdwControls)
00497 {
00498     MIXERLINECONTROLSW  mlcW;
00499     DWORD       ret;
00500     unsigned int    i;
00501 
00502     TRACE("(%p, %p, %08x)\n", hmix, lpmlcA, fdwControls);
00503 
00504     if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA) ||
00505     lpmlcA->cbmxctrl != sizeof(MIXERCONTROLA))
00506     return MMSYSERR_INVALPARAM;
00507 
00508     mlcW.cbStruct = sizeof(mlcW);
00509     mlcW.dwLineID = lpmlcA->dwLineID;
00510     mlcW.u.dwControlID = lpmlcA->u.dwControlID;
00511     mlcW.u.dwControlType = lpmlcA->u.dwControlType;
00512 
00513     /* Debugging on Windows shows for MIXER_GETLINECONTROLSF_ONEBYTYPE only,
00514        the control count is assumed to be 1 - This is relied upon by a game,
00515        "Dynomite Deluze"                                                    */
00516     if (MIXER_GETLINECONTROLSF_ONEBYTYPE == (fdwControls & MIXER_GETLINECONTROLSF_QUERYMASK)) {
00517         mlcW.cControls = 1;
00518     } else {
00519         mlcW.cControls = lpmlcA->cControls;
00520     }
00521     mlcW.cbmxctrl = sizeof(MIXERCONTROLW);
00522     mlcW.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
00523                   mlcW.cControls * mlcW.cbmxctrl);
00524 
00525     ret = mixerGetLineControlsW(hmix, &mlcW, fdwControls);
00526 
00527     if (ret == MMSYSERR_NOERROR) {
00528     lpmlcA->dwLineID = mlcW.dwLineID;
00529     lpmlcA->u.dwControlID = mlcW.u.dwControlID;
00530     lpmlcA->u.dwControlType = mlcW.u.dwControlType;
00531 
00532     for (i = 0; i < mlcW.cControls; i++) {
00533         lpmlcA->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLA);
00534         lpmlcA->pamxctrl[i].dwControlID = mlcW.pamxctrl[i].dwControlID;
00535         lpmlcA->pamxctrl[i].dwControlType = mlcW.pamxctrl[i].dwControlType;
00536         lpmlcA->pamxctrl[i].fdwControl = mlcW.pamxctrl[i].fdwControl;
00537         lpmlcA->pamxctrl[i].cMultipleItems = mlcW.pamxctrl[i].cMultipleItems;
00538             WideCharToMultiByte( CP_ACP, 0, mlcW.pamxctrl[i].szShortName, -1,
00539                                  lpmlcA->pamxctrl[i].szShortName,
00540                                  sizeof(lpmlcA->pamxctrl[i].szShortName), NULL, NULL );
00541             WideCharToMultiByte( CP_ACP, 0, mlcW.pamxctrl[i].szName, -1,
00542                                  lpmlcA->pamxctrl[i].szName,
00543                                  sizeof(lpmlcA->pamxctrl[i].szName), NULL, NULL );
00544         /* sizeof(lpmlcA->pamxctrl[i].Bounds) ==
00545          * sizeof(mlcW.pamxctrl[i].Bounds) */
00546         memcpy(&lpmlcA->pamxctrl[i].Bounds, &mlcW.pamxctrl[i].Bounds,
00547            sizeof(mlcW.pamxctrl[i].Bounds));
00548         /* sizeof(lpmlcA->pamxctrl[i].Metrics) ==
00549          * sizeof(mlcW.pamxctrl[i].Metrics) */
00550         memcpy(&lpmlcA->pamxctrl[i].Metrics, &mlcW.pamxctrl[i].Metrics,
00551            sizeof(mlcW.pamxctrl[i].Metrics));
00552     }
00553     }
00554 
00555     HeapFree(GetProcessHeap(), 0, mlcW.pamxctrl);
00556 
00557     return ret;
00558 }
00559 
00560 /**************************************************************************
00561  *              mixerGetLineControlsW       [WINMM.@]
00562  */
00563 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
00564                   DWORD fdwControls)
00565 {
00566     LPWINE_MIXER    lpwm;
00567     UINT        uRet = MMSYSERR_NOERROR;
00568 
00569     TRACE("(%p, %p, %08x)\n", hmix, lpmlcW, fdwControls);
00570 
00571     if ((uRet = MIXER_GetDev(hmix, fdwControls, &lpwm)) != MMSYSERR_NOERROR)
00572     return uRet;
00573 
00574     if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW))
00575     return MMSYSERR_INVALPARAM;
00576 
00577     return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD_PTR)lpmlcW,
00578              fdwControls);
00579 }
00580 
00581 /**************************************************************************
00582  *              mixerGetLineInfoW       [WINMM.@]
00583  */
00584 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW, DWORD fdwInfo)
00585 {
00586     LPWINE_MIXER    lpwm;
00587     UINT        uRet = MMSYSERR_NOERROR;
00588 
00589     TRACE("(%p, %p, %08x)\n", hmix, lpmliW, fdwInfo);
00590 
00591     if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW))
00592     return MMSYSERR_INVALPARAM;
00593     
00594     if ((uRet = MIXER_GetDev(hmix, fdwInfo, &lpwm)) != MMSYSERR_NOERROR)
00595     return uRet;
00596 
00597     return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD_PTR)lpmliW,
00598              fdwInfo);
00599 }
00600 
00601 /**************************************************************************
00602  *              mixerGetLineInfoA       [WINMM.@]
00603  */
00604 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliA,
00605                   DWORD fdwInfo)
00606 {
00607     MIXERLINEW      mliW;
00608     UINT        ret;
00609 
00610     TRACE("(%p, %p, %08x)\n", hmix, lpmliA, fdwInfo);
00611 
00612     if (lpmliA == NULL || lpmliA->cbStruct != sizeof(*lpmliA))
00613     return MMSYSERR_INVALPARAM;
00614 
00615     mliW.cbStruct = sizeof(mliW);
00616     switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
00617     case MIXER_GETLINEINFOF_COMPONENTTYPE:
00618     mliW.dwComponentType = lpmliA->dwComponentType;
00619     break;
00620     case MIXER_GETLINEINFOF_DESTINATION:
00621     mliW.dwDestination = lpmliA->dwDestination;
00622     break;
00623     case MIXER_GETLINEINFOF_LINEID:
00624     mliW.dwLineID = lpmliA->dwLineID;
00625     break;
00626     case MIXER_GETLINEINFOF_SOURCE:
00627     mliW.dwDestination = lpmliA->dwDestination;
00628     mliW.dwSource = lpmliA->dwSource;
00629     break;
00630     case MIXER_GETLINEINFOF_TARGETTYPE:
00631     mliW.Target.dwType = lpmliA->Target.dwType;
00632     mliW.Target.wMid = lpmliA->Target.wMid;
00633     mliW.Target.wPid = lpmliA->Target.wPid;
00634     mliW.Target.vDriverVersion = lpmliA->Target.vDriverVersion;
00635         MultiByteToWideChar( CP_ACP, 0, lpmliA->Target.szPname, -1, mliW.Target.szPname, sizeof(mliW.Target.szPname)/sizeof(WCHAR));
00636     break;
00637     default:
00638     WARN("Unsupported fdwControls=0x%08x\n", fdwInfo);
00639         return MMSYSERR_INVALFLAG;
00640     }
00641 
00642     ret = mixerGetLineInfoW(hmix, &mliW, fdwInfo);
00643 
00644     if(ret == MMSYSERR_NOERROR)
00645     {
00646         lpmliA->dwDestination = mliW.dwDestination;
00647         lpmliA->dwSource = mliW.dwSource;
00648         lpmliA->dwLineID = mliW.dwLineID;
00649         lpmliA->fdwLine = mliW.fdwLine;
00650         lpmliA->dwUser = mliW.dwUser;
00651         lpmliA->dwComponentType = mliW.dwComponentType;
00652         lpmliA->cChannels = mliW.cChannels;
00653         lpmliA->cConnections = mliW.cConnections;
00654         lpmliA->cControls = mliW.cControls;
00655         WideCharToMultiByte( CP_ACP, 0, mliW.szShortName, -1, lpmliA->szShortName,
00656                              sizeof(lpmliA->szShortName), NULL, NULL);
00657         WideCharToMultiByte( CP_ACP, 0, mliW.szName, -1, lpmliA->szName,
00658                              sizeof(lpmliA->szName), NULL, NULL );
00659         lpmliA->Target.dwType = mliW.Target.dwType;
00660         lpmliA->Target.dwDeviceID = mliW.Target.dwDeviceID;
00661         lpmliA->Target.wMid = mliW.Target.wMid;
00662         lpmliA->Target.wPid = mliW.Target.wPid;
00663         lpmliA->Target.vDriverVersion = mliW.Target.vDriverVersion;
00664         WideCharToMultiByte( CP_ACP, 0, mliW.Target.szPname, -1, lpmliA->Target.szPname,
00665                              sizeof(lpmliA->Target.szPname), NULL, NULL );
00666     }
00667     return ret;
00668 }
00669 
00670 /**************************************************************************
00671  *              mixerSetControlDetails  [WINMM.@]
00672  */
00673 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd,
00674                    DWORD fdwDetails)
00675 {
00676     LPWINE_MIXER    lpwm;
00677     UINT        uRet = MMSYSERR_NOERROR;
00678 
00679     TRACE("(%p, %p, %08x)\n", hmix, lpmcd, fdwDetails);
00680 
00681     if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR)
00682     return uRet;
00683 
00684     return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD_PTR)lpmcd,
00685              fdwDetails);
00686 }
00687 
00688 /**************************************************************************
00689  *              mixerMessage        [WINMM.@]
00690  */
00691 DWORD WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
00692 {
00693     LPWINE_MLD      wmld;
00694 
00695     TRACE("(%p, %d, %08lx, %08lx): semi-stub?\n",
00696       hmix, uMsg, dwParam1, dwParam2);
00697 
00698     if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
00699     return MMSYSERR_INVALHANDLE;
00700 
00701     return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2);
00702 }
00703 
00704 /**************************************************************************
00705  *              auxGetNumDevs       [WINMM.@]
00706  */
00707 UINT WINAPI auxGetNumDevs(void)
00708 {
00709     return MMDRV_GetNum(MMDRV_AUX);
00710 }
00711 
00712 /**************************************************************************
00713  *              auxGetDevCapsW      [WINMM.@]
00714  */
00715 UINT WINAPI auxGetDevCapsW(UINT_PTR uDeviceID, LPAUXCAPSW lpCaps, UINT uSize)
00716 {
00717     LPWINE_MLD      wmld;
00718 
00719     TRACE("(%04lX, %p, %d) !\n", uDeviceID, lpCaps, uSize);
00720 
00721     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
00722 
00723     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL)
00724     return MMSYSERR_INVALHANDLE;
00725     return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize);
00726 }
00727 
00728 /**************************************************************************
00729  *              auxGetDevCapsA      [WINMM.@]
00730  */
00731 UINT WINAPI auxGetDevCapsA(UINT_PTR uDeviceID, LPAUXCAPSA lpCaps, UINT uSize)
00732 {
00733     AUXCAPSW    acW;
00734     UINT    ret;
00735 
00736     if (lpCaps == NULL)        return MMSYSERR_INVALPARAM;
00737 
00738     ret = auxGetDevCapsW(uDeviceID, &acW, sizeof(acW));
00739 
00740     if (ret == MMSYSERR_NOERROR) {
00741     AUXCAPSA acA;
00742     acA.wMid           = acW.wMid;
00743     acA.wPid           = acW.wPid;
00744     acA.vDriverVersion = acW.vDriverVersion;
00745     WideCharToMultiByte( CP_ACP, 0, acW.szPname, -1, acA.szPname,
00746                              sizeof(acA.szPname), NULL, NULL );
00747     acA.wTechnology    = acW.wTechnology;
00748     acA.dwSupport      = acW.dwSupport;
00749     memcpy(lpCaps, &acA, min(uSize, sizeof(acA)));
00750     }
00751     return ret;
00752 }
00753 
00754 /**************************************************************************
00755  *              auxGetVolume        [WINMM.@]
00756  */
00757 UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume)
00758 {
00759     LPWINE_MLD      wmld;
00760 
00761     TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume);
00762 
00763     if ((wmld = MMDRV_Get(UlongToHandle(uDeviceID), MMDRV_AUX, TRUE)) == NULL)
00764     return MMSYSERR_INVALHANDLE;
00765     return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L);
00766 }
00767 
00768 /**************************************************************************
00769  *              auxSetVolume        [WINMM.@]
00770  */
00771 UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume)
00772 {
00773     LPWINE_MLD      wmld;
00774 
00775     TRACE("(%04X, %u) !\n", uDeviceID, dwVolume);
00776 
00777     if ((wmld = MMDRV_Get(UlongToHandle(uDeviceID), MMDRV_AUX, TRUE)) == NULL)
00778     return MMSYSERR_INVALHANDLE;
00779     return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L);
00780 }
00781 
00782 /**************************************************************************
00783  *              auxOutMessage       [WINMM.@]
00784  */
00785 UINT WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD_PTR dw1, DWORD_PTR dw2)
00786 {
00787     LPWINE_MLD      wmld;
00788 
00789     if ((wmld = MMDRV_Get(UlongToHandle(uDeviceID), MMDRV_AUX, TRUE)) == NULL)
00790     return MMSYSERR_INVALHANDLE;
00791 
00792     return MMDRV_Message(wmld, uMessage, dw1, dw2);
00793 }
00794 
00795 /**************************************************************************
00796  *              midiOutGetNumDevs   [WINMM.@]
00797  */
00798 UINT WINAPI midiOutGetNumDevs(void)
00799 {
00800     return MMDRV_GetNum(MMDRV_MIDIOUT);
00801 }
00802 
00803 /**************************************************************************
00804  *              midiOutGetDevCapsW  [WINMM.@]
00805  */
00806 UINT WINAPI midiOutGetDevCapsW(UINT_PTR uDeviceID, LPMIDIOUTCAPSW lpCaps,
00807                    UINT uSize)
00808 {
00809     LPWINE_MLD  wmld;
00810 
00811     TRACE("(%lu, %p, %u);\n", uDeviceID, lpCaps, uSize);
00812 
00813     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
00814 
00815     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL)
00816     return MMSYSERR_INVALHANDLE;
00817 
00818     return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize);
00819 }
00820 
00821 /**************************************************************************
00822  *              midiOutGetDevCapsA  [WINMM.@]
00823  */
00824 UINT WINAPI midiOutGetDevCapsA(UINT_PTR uDeviceID, LPMIDIOUTCAPSA lpCaps,
00825                    UINT uSize)
00826 {
00827     MIDIOUTCAPSW    mocW;
00828     UINT        ret;
00829 
00830     if (lpCaps == NULL)        return MMSYSERR_INVALPARAM;
00831 
00832     ret = midiOutGetDevCapsW(uDeviceID, &mocW, sizeof(mocW));
00833 
00834     if (ret == MMSYSERR_NOERROR) {
00835     MIDIOUTCAPSA mocA;
00836     mocA.wMid       = mocW.wMid;
00837     mocA.wPid       = mocW.wPid;
00838     mocA.vDriverVersion = mocW.vDriverVersion;
00839     WideCharToMultiByte( CP_ACP, 0, mocW.szPname, -1, mocA.szPname,
00840                              sizeof(mocA.szPname), NULL, NULL );
00841     mocA.wTechnology        = mocW.wTechnology;
00842     mocA.wVoices        = mocW.wVoices;
00843     mocA.wNotes     = mocW.wNotes;
00844     mocA.wChannelMask   = mocW.wChannelMask;
00845     mocA.dwSupport          = mocW.dwSupport;
00846     memcpy(lpCaps, &mocA, min(uSize, sizeof(mocA)));
00847     }
00848     return ret;
00849 }
00850 
00851 /**************************************************************************
00852  *              midiOutGetErrorTextA    [WINMM.@]
00853  *              midiInGetErrorTextA     [WINMM.@]
00854  */
00855 UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
00856 {
00857     UINT    ret;
00858 
00859     if (lpText == NULL) ret = MMSYSERR_INVALPARAM;
00860     else if (uSize == 0) ret = MMSYSERR_NOERROR;
00861     else
00862     {
00863         LPWSTR  xstr = HeapAlloc(GetProcessHeap(), 0, uSize * sizeof(WCHAR));
00864         if (!xstr) ret = MMSYSERR_NOMEM;
00865         else
00866         {
00867             ret = midiOutGetErrorTextW(uError, xstr, uSize);
00868             if (ret == MMSYSERR_NOERROR)
00869                 WideCharToMultiByte(CP_ACP, 0, xstr, -1, lpText, uSize, NULL, NULL);
00870             HeapFree(GetProcessHeap(), 0, xstr);
00871         }
00872     }
00873     return ret;
00874 }
00875 
00876 /**************************************************************************
00877  *              midiOutGetErrorTextW    [WINMM.@]
00878  *              midiInGetErrorTextW     [WINMM.@]
00879  */
00880 UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
00881 {
00882     UINT        ret = MMSYSERR_BADERRNUM;
00883 
00884     if (lpText == NULL) ret = MMSYSERR_INVALPARAM;
00885     else if (uSize == 0) ret = MMSYSERR_NOERROR;
00886     else if (
00887            /* test has been removed because MMSYSERR_BASE is 0, and gcc did emit
00888         * a warning for the test was always true */
00889            (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
00890            (uError >= MIDIERR_BASE  && uError <= MIDIERR_LASTERROR)) {
00891     if (LoadStringW(hWinMM32Instance, uError, lpText, uSize) > 0) {
00892         ret = MMSYSERR_NOERROR;
00893     }
00894     }
00895     return ret;
00896 }
00897 
00898 /**************************************************************************
00899  *              MIDI_OutAlloc           [internal]
00900  */
00901 static  LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, DWORD_PTR* lpdwCallback,
00902                       DWORD_PTR* lpdwInstance, LPDWORD lpdwFlags,
00903                       DWORD cIDs, MIDIOPENSTRMID* lpIDs)
00904 {
00905     HANDLE          hMidiOut;
00906     LPWINE_MIDI     lpwm;
00907     UINT        size;
00908 
00909     size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID);
00910 
00911     lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags,
00912                     lpdwCallback, lpdwInstance);
00913 
00914     if (lphMidiOut != NULL)
00915     *lphMidiOut = hMidiOut;
00916 
00917     if (lpwm) {
00918         lpwm->mod.hMidi = hMidiOut;
00919     lpwm->mod.dwCallback = *lpdwCallback;
00920     lpwm->mod.dwInstance = *lpdwInstance;
00921     lpwm->mod.dnDevNode = 0;
00922     lpwm->mod.cIds = cIDs;
00923     if (cIDs)
00924         memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID));
00925     }
00926     return lpwm;
00927 }
00928 
00929 /**************************************************************************
00930  *              midiOutOpen         [WINMM.@]
00931  */
00932 MMRESULT WINAPI midiOutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID,
00933                        DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
00934 {
00935     HMIDIOUT        hMidiOut;
00936     LPWINE_MIDI     lpwm;
00937     UINT        dwRet = 0;
00938 
00939     TRACE("(%p, %d, %08lX, %08lX, %08X);\n",
00940       lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
00941 
00942     if (lphMidiOut != NULL) *lphMidiOut = 0;
00943 
00944     lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags, 0, NULL);
00945 
00946     if (lpwm == NULL)
00947     return MMSYSERR_NOMEM;
00948 
00949     lpwm->mld.uDeviceID = uDeviceID;
00950 
00951     dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD_PTR)&lpwm->mod, dwFlags);
00952 
00953     if (dwRet != MMSYSERR_NOERROR) {
00954     MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm);
00955     hMidiOut = 0;
00956     }
00957 
00958     if (lphMidiOut) *lphMidiOut = hMidiOut;
00959     TRACE("=> %d hMidi=%p\n", dwRet, hMidiOut);
00960 
00961     return dwRet;
00962 }
00963 
00964 /**************************************************************************
00965  *              midiOutClose        [WINMM.@]
00966  */
00967 UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
00968 {
00969     LPWINE_MLD      wmld;
00970     DWORD       dwRet;
00971 
00972     TRACE("(%p)\n", hMidiOut);
00973 
00974     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
00975     return MMSYSERR_INVALHANDLE;
00976 
00977     dwRet = MMDRV_Close(wmld, MODM_CLOSE);
00978     MMDRV_Free(hMidiOut, wmld);
00979 
00980     return dwRet;
00981 }
00982 
00983 /**************************************************************************
00984  *              midiOutPrepareHeader    [WINMM.@]
00985  */
00986 UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
00987                  MIDIHDR* lpMidiOutHdr, UINT uSize)
00988 {
00989     LPWINE_MLD      wmld;
00990 
00991     TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
00992 
00993     if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR))
00994     return MMSYSERR_INVALPARAM;
00995 
00996     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
00997     return MMSYSERR_INVALHANDLE;
00998 
00999     return MMDRV_Message(wmld, MODM_PREPARE, (DWORD_PTR)lpMidiOutHdr, uSize);
01000 }
01001 
01002 /**************************************************************************
01003  *              midiOutUnprepareHeader  [WINMM.@]
01004  */
01005 UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
01006                    MIDIHDR* lpMidiOutHdr, UINT uSize)
01007 {
01008     LPWINE_MLD      wmld;
01009 
01010     TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
01011 
01012     if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR))
01013     return MMSYSERR_INVALPARAM;
01014 
01015     if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
01016     return MMSYSERR_NOERROR;
01017     }
01018 
01019     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
01020     return MMSYSERR_INVALHANDLE;
01021 
01022     return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD_PTR)lpMidiOutHdr, uSize);
01023 }
01024 
01025 /**************************************************************************
01026  *              midiOutShortMsg     [WINMM.@]
01027  */
01028 UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
01029 {
01030     LPWINE_MLD      wmld;
01031 
01032     TRACE("(%p, %08X)\n", hMidiOut, dwMsg);
01033 
01034     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
01035     return MMSYSERR_INVALHANDLE;
01036 
01037     return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L);
01038 }
01039 
01040 /**************************************************************************
01041  *              midiOutLongMsg      [WINMM.@]
01042  */
01043 UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
01044                MIDIHDR* lpMidiOutHdr, UINT uSize)
01045 {
01046     LPWINE_MLD      wmld;
01047 
01048     TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize);
01049 
01050     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
01051     return MMSYSERR_INVALHANDLE;
01052 
01053     return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD_PTR)lpMidiOutHdr, uSize);
01054 }
01055 
01056 /**************************************************************************
01057  *              midiOutReset        [WINMM.@]
01058  */
01059 UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
01060 {
01061     LPWINE_MLD      wmld;
01062 
01063     TRACE("(%p)\n", hMidiOut);
01064 
01065     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
01066     return MMSYSERR_INVALHANDLE;
01067 
01068     return MMDRV_Message(wmld, MODM_RESET, 0L, 0L);
01069 }
01070 
01071 /**************************************************************************
01072  *              midiOutGetVolume    [WINMM.@]
01073  */
01074 UINT WINAPI midiOutGetVolume(HMIDIOUT hMidiOut, DWORD* lpdwVolume)
01075 {
01076     LPWINE_MLD      wmld;
01077 
01078     TRACE("(%p, %p);\n", hMidiOut, lpdwVolume);
01079 
01080     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
01081     return MMSYSERR_INVALHANDLE;
01082 
01083     return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L);
01084 }
01085 
01086 /**************************************************************************
01087  *              midiOutSetVolume    [WINMM.@]
01088  */
01089 UINT WINAPI midiOutSetVolume(HMIDIOUT hMidiOut, DWORD dwVolume)
01090 {
01091     LPWINE_MLD      wmld;
01092 
01093     TRACE("(%p, %d);\n", hMidiOut, dwVolume);
01094 
01095     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL)
01096     return MMSYSERR_INVALHANDLE;
01097 
01098     return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L);
01099 }
01100 
01101 /**************************************************************************
01102  *              midiOutCachePatches     [WINMM.@]
01103  */
01104 UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank,
01105                 WORD* lpwPatchArray, UINT uFlags)
01106 {
01107     /* not really necessary to support this */
01108     FIXME("not supported yet\n");
01109     return MMSYSERR_NOTSUPPORTED;
01110 }
01111 
01112 /**************************************************************************
01113  *              midiOutCacheDrumPatches [WINMM.@]
01114  */
01115 UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch,
01116                     WORD* lpwKeyArray, UINT uFlags)
01117 {
01118     FIXME("not supported yet\n");
01119     return MMSYSERR_NOTSUPPORTED;
01120 }
01121 
01122 /**************************************************************************
01123  *              midiOutGetID        [WINMM.@]
01124  */
01125 UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID)
01126 {
01127     LPWINE_MLD      wmld;
01128 
01129     TRACE("(%p, %p)\n", hMidiOut, lpuDeviceID);
01130 
01131     if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
01132     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL)
01133     return MMSYSERR_INVALHANDLE;
01134 
01135     *lpuDeviceID = wmld->uDeviceID;
01136     return MMSYSERR_NOERROR;
01137 }
01138 
01139 /**************************************************************************
01140  *              midiOutMessage      [WINMM.@]
01141  */
01142 UINT WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage,
01143                            DWORD_PTR dwParam1, DWORD_PTR dwParam2)
01144 {
01145     LPWINE_MLD      wmld;
01146 
01147     TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2);
01148 
01149     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) {
01150     /* HACK... */
01151     if (uMessage == 0x0001) {
01152         *(LPDWORD)dwParam1 = 1;
01153         return 0;
01154     }
01155     if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) {
01156         return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
01157     }
01158     return MMSYSERR_INVALHANDLE;
01159     }
01160 
01161     switch (uMessage) {
01162     case MODM_OPEN:
01163     case MODM_CLOSE:
01164     FIXME("can't handle OPEN or CLOSE message!\n");
01165     return MMSYSERR_NOTSUPPORTED;
01166     }
01167     return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2);
01168 }
01169 
01170 /**************************************************************************
01171  *              midiInGetNumDevs    [WINMM.@]
01172  */
01173 UINT WINAPI midiInGetNumDevs(void)
01174 {
01175     return MMDRV_GetNum(MMDRV_MIDIIN);
01176 }
01177 
01178 /**************************************************************************
01179  *              midiInGetDevCapsW   [WINMM.@]
01180  */
01181 UINT WINAPI midiInGetDevCapsW(UINT_PTR uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize)
01182 {
01183     LPWINE_MLD  wmld;
01184 
01185     TRACE("(%ld, %p, %d);\n", uDeviceID, lpCaps, uSize);
01186 
01187     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
01188 
01189     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL)
01190     return MMSYSERR_INVALHANDLE;
01191 
01192    return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize);
01193 }
01194 
01195 /**************************************************************************
01196  *              midiInGetDevCapsA   [WINMM.@]
01197  */
01198 UINT WINAPI midiInGetDevCapsA(UINT_PTR uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize)
01199 {
01200     MIDIINCAPSW     micW;
01201     UINT        ret;
01202 
01203     if (lpCaps == NULL)        return MMSYSERR_INVALPARAM;
01204 
01205     ret = midiInGetDevCapsW(uDeviceID, &micW, sizeof(micW));
01206 
01207     if (ret == MMSYSERR_NOERROR) {
01208     MIDIINCAPSA micA;
01209     micA.wMid           = micW.wMid;
01210     micA.wPid           = micW.wPid;
01211     micA.vDriverVersion = micW.vDriverVersion;
01212         WideCharToMultiByte( CP_ACP, 0, micW.szPname, -1, micA.szPname,
01213                              sizeof(micA.szPname), NULL, NULL );
01214     micA.dwSupport      = micW.dwSupport;
01215     memcpy(lpCaps, &micA, min(uSize, sizeof(micA)));
01216     }
01217     return ret;
01218 }
01219 
01220 /**************************************************************************
01221  *              midiInOpen      [WINMM.@]
01222  */
01223 MMRESULT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID,
01224                DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
01225 {
01226     HANDLE      hMidiIn;
01227     LPWINE_MIDI     lpwm;
01228     DWORD       dwRet = 0;
01229 
01230     TRACE("(%p, %d, %08lX, %08lX, %08X);\n",
01231       lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags);
01232 
01233     if (lphMidiIn != NULL) *lphMidiIn = 0;
01234 
01235     lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn,
01236                     &dwFlags, &dwCallback, &dwInstance);
01237 
01238     if (lpwm == NULL)
01239     return MMSYSERR_NOMEM;
01240 
01241     lpwm->mod.hMidi = hMidiIn;
01242     lpwm->mod.dwCallback = dwCallback;
01243     lpwm->mod.dwInstance = dwInstance;
01244 
01245     lpwm->mld.uDeviceID = uDeviceID;
01246     dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD_PTR)&lpwm->mod, dwFlags);
01247 
01248     if (dwRet != MMSYSERR_NOERROR) {
01249     MMDRV_Free(hMidiIn, &lpwm->mld);
01250     hMidiIn = 0;
01251     }
01252     if (lphMidiIn != NULL) *lphMidiIn = hMidiIn;
01253     TRACE("=> %d hMidi=%p\n", dwRet, hMidiIn);
01254 
01255     return dwRet;
01256 }
01257 
01258 /**************************************************************************
01259  *              midiInClose     [WINMM.@]
01260  */
01261 UINT WINAPI midiInClose(HMIDIIN hMidiIn)
01262 {
01263     LPWINE_MLD      wmld;
01264     DWORD       dwRet;
01265 
01266     TRACE("(%p)\n", hMidiIn);
01267 
01268     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
01269     return MMSYSERR_INVALHANDLE;
01270 
01271     dwRet = MMDRV_Close(wmld, MIDM_CLOSE);
01272     MMDRV_Free(hMidiIn, wmld);
01273     return dwRet;
01274 }
01275 
01276 /**************************************************************************
01277  *              midiInPrepareHeader [WINMM.@]
01278  */
01279 UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
01280                 MIDIHDR* lpMidiInHdr, UINT uSize)
01281 {
01282     LPWINE_MLD      wmld;
01283 
01284     TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
01285 
01286     if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR))
01287     return MMSYSERR_INVALPARAM;
01288 
01289     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
01290     return MMSYSERR_INVALHANDLE;
01291 
01292     return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD_PTR)lpMidiInHdr, uSize);
01293 }
01294 
01295 /**************************************************************************
01296  *              midiInUnprepareHeader   [WINMM.@]
01297  */
01298 UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
01299                   MIDIHDR* lpMidiInHdr, UINT uSize)
01300 {
01301     LPWINE_MLD      wmld;
01302 
01303     TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
01304 
01305     if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR))
01306     return MMSYSERR_INVALPARAM;
01307 
01308     if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
01309     return MMSYSERR_NOERROR;
01310     }
01311 
01312     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
01313     return MMSYSERR_INVALHANDLE;
01314 
01315     return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD_PTR)lpMidiInHdr, uSize);
01316 }
01317 
01318 /**************************************************************************
01319  *              midiInAddBuffer     [WINMM.@]
01320  */
01321 UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
01322                 MIDIHDR* lpMidiInHdr, UINT uSize)
01323 {
01324     LPWINE_MLD      wmld;
01325 
01326     TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize);
01327 
01328     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
01329     return MMSYSERR_INVALHANDLE;
01330 
01331     return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD_PTR)lpMidiInHdr, uSize);
01332 }
01333 
01334 /**************************************************************************
01335  *              midiInStart         [WINMM.@]
01336  */
01337 UINT WINAPI midiInStart(HMIDIIN hMidiIn)
01338 {
01339     LPWINE_MLD      wmld;
01340 
01341     TRACE("(%p)\n", hMidiIn);
01342 
01343     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
01344     return MMSYSERR_INVALHANDLE;
01345 
01346     return MMDRV_Message(wmld, MIDM_START, 0L, 0L);
01347 }
01348 
01349 /**************************************************************************
01350  *              midiInStop          [WINMM.@]
01351  */
01352 UINT WINAPI midiInStop(HMIDIIN hMidiIn)
01353 {
01354     LPWINE_MLD      wmld;
01355 
01356     TRACE("(%p)\n", hMidiIn);
01357 
01358     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
01359     return MMSYSERR_INVALHANDLE;
01360 
01361     return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L);
01362 }
01363 
01364 /**************************************************************************
01365  *              midiInReset         [WINMM.@]
01366  */
01367 UINT WINAPI midiInReset(HMIDIIN hMidiIn)
01368 {
01369     LPWINE_MLD      wmld;
01370 
01371     TRACE("(%p)\n", hMidiIn);
01372 
01373     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
01374     return MMSYSERR_INVALHANDLE;
01375 
01376     return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L);
01377 }
01378 
01379 /**************************************************************************
01380  *              midiInGetID         [WINMM.@]
01381  */
01382 UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID)
01383 {
01384     LPWINE_MLD      wmld;
01385 
01386     TRACE("(%p, %p)\n", hMidiIn, lpuDeviceID);
01387 
01388     if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM;
01389 
01390     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL)
01391     return MMSYSERR_INVALHANDLE;
01392 
01393     *lpuDeviceID = wmld->uDeviceID;
01394 
01395     return MMSYSERR_NOERROR;
01396 }
01397 
01398 /**************************************************************************
01399  *              midiInMessage       [WINMM.@]
01400  */
01401 UINT WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage,
01402                           DWORD_PTR dwParam1, DWORD_PTR dwParam2)
01403 {
01404     LPWINE_MLD      wmld;
01405 
01406     TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2);
01407 
01408     if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL)
01409     return MMSYSERR_INVALHANDLE;
01410 
01411     switch (uMessage) {
01412     case MIDM_OPEN:
01413     case MIDM_CLOSE:
01414     FIXME("can't handle OPEN or CLOSE message!\n");
01415     return MMSYSERR_NOTSUPPORTED;
01416     }
01417     return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2);
01418 }
01419 
01420 /**************************************************************************
01421  *              midiConnect         [WINMM.@]
01422  */
01423 MMRESULT WINAPI midiConnect(HMIDI hMidi, HMIDIOUT hmo, LPVOID pReserved)
01424 {
01425     FIXME("(%p, %p, %p): Stub\n", hMidi, hmo, pReserved);
01426     return MMSYSERR_ERROR;
01427 }
01428 
01429 /**************************************************************************
01430  *              midiDisconnect          [WINMM.@]
01431  */
01432 MMRESULT WINAPI midiDisconnect(HMIDI hMidi, HMIDIOUT hmo, LPVOID pReserved)
01433 {
01434     FIXME("(%p, %p, %p): Stub\n", hMidi, hmo, pReserved);
01435     return MMSYSERR_ERROR;
01436 }
01437 
01438 typedef struct WINE_MIDIStream {
01439     HMIDIOUT            hDevice;
01440     HANDLE          hThread;
01441     DWORD           dwThreadID;
01442     DWORD           dwTempo;
01443     DWORD           dwTimeDiv;
01444     DWORD           dwPositionMS;
01445     DWORD           dwPulses;
01446     DWORD           dwStartTicks;
01447     WORD            wFlags;
01448     HANDLE          hEvent;
01449     LPMIDIHDR           lpMidiHdr;
01450 } WINE_MIDIStream;
01451 
01452 #define WINE_MSM_HEADER     (WM_USER+0)
01453 #define WINE_MSM_STOP       (WM_USER+1)
01454 
01455 /**************************************************************************
01456  *              MMSYSTEM_GetMidiStream      [internal]
01457  */
01458 static  BOOL    MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm)
01459 {
01460     WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE);
01461 
01462     if (lplpwm)
01463     *lplpwm = lpwm;
01464 
01465     if (lpwm == NULL) {
01466     return FALSE;
01467     }
01468 
01469     *lpMidiStrm = (WINE_MIDIStream*)(ULONG_PTR)lpwm->mod.rgIds.dwStreamID; // FIXME: not 64 bit safe
01470 
01471     return *lpMidiStrm != NULL;
01472 }
01473 
01474 /**************************************************************************
01475  *              MMSYSTEM_MidiStream_Convert [internal]
01476  */
01477 static  DWORD   MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse)
01478 {
01479     DWORD   ret = 0;
01480 
01481     if (lpMidiStrm->dwTimeDiv == 0) {
01482     FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n");
01483     } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */
01484     int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv);  /* number of frames     */
01485     int nsf = LOBYTE(lpMidiStrm->dwTimeDiv);        /* number of sub-frames */
01486     ret = (pulse * 1000) / (nf * nsf);
01487     } else {
01488     ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) /
01489               (double)lpMidiStrm->dwTimeDiv);
01490     }
01491 
01492     return ret;
01493 }
01494 
01495 /**************************************************************************
01496  *          MMSYSTEM_MidiStream_MessageHandler  [internal]
01497  */
01498 static  BOOL    MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg)
01499 {
01500     LPMIDIHDR   lpMidiHdr;
01501     LPMIDIHDR*  lpmh;
01502     LPBYTE  lpData;
01503 
01504     switch (msg->message) {
01505     case WM_QUIT:
01506     SetEvent(lpMidiStrm->hEvent);
01507     return FALSE;
01508     case WINE_MSM_STOP:
01509     TRACE("STOP\n");
01510     /* this is not quite what MS doc says... */
01511     midiOutReset(lpMidiStrm->hDevice);
01512     /* empty list of already submitted buffers */
01513     for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = lpMidiHdr->lpNext) {
01514         lpMidiHdr->dwFlags |= MHDR_DONE;
01515         lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
01516 
01517         DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
01518                (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
01519                lpwm->mod.dwInstance, (DWORD_PTR)lpMidiHdr, 0);
01520     }
01521     lpMidiStrm->lpMidiHdr = 0;
01522     SetEvent(lpMidiStrm->hEvent);
01523     break;
01524     case WINE_MSM_HEADER:
01525     /* sets initial tick count for first MIDIHDR */
01526     if (!lpMidiStrm->dwStartTicks)
01527         lpMidiStrm->dwStartTicks = GetTickCount();
01528 
01529     /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent
01530      * by native mcimidi, it doesn't look like a correct one".
01531      * this trick allows to throw it away... but I don't like it.
01532      * It looks like part of the file I'm trying to play and definitively looks
01533      * like raw midi content
01534      * I'd really like to understand why native mcimidi sends it. Perhaps a bad
01535      * synchronization issue where native mcimidi is still processing raw MIDI
01536      * content before generating MIDIEVENTs ?
01537      *
01538      * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^..
01539      * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b..
01540      * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^.
01541      * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x.
01542      * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^
01543      * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b
01544      * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..#
01545      * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L..
01546      * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H..
01547      * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?.
01548      * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E.
01549      * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F
01550      * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H
01551      * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.;
01552      * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.;
01553      * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|.
01554      * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|.
01555      */
01556     lpMidiHdr = (LPMIDIHDR)msg->lParam;
01557     lpData = (LPBYTE)lpMidiHdr->lpData;
01558     TRACE("Adding %s lpMidiHdr=%p [lpData=0x%p dwBufferLength=%u/%u dwFlags=0x%08x size=%lu]\n",
01559           (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr,
01560           lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded,
01561           lpMidiHdr->dwFlags, msg->wParam);
01562 #if 0
01563     /* dumps content of lpMidiHdr->lpData
01564      * FIXME: there should be a debug routine somewhere that already does this
01565      * I hate spreading this type of shit all around the code
01566      */
01567     for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) {
01568         DWORD   i;
01569         BYTE    ch;
01570 
01571         for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++)
01572         printf("%02x ", lpData[dwToGo + i]);
01573         for (; i < 16; i++)
01574         printf("   ");
01575         for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) {
01576         ch = lpData[dwToGo + i];
01577         printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.');
01578         }
01579         printf("\n");
01580     }
01581 #endif
01582     if (((LPMIDIEVENT)lpData)->dwStreamID != 0 &&
01583         ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF &&
01584         /* FIXME: not 64 bit safe */
01585         ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD_PTR)lpMidiStrm) {
01586         FIXME("Dropping bad %s lpMidiHdr (streamID=%08x)\n",
01587           (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular",
01588           ((LPMIDIEVENT)lpData)->dwStreamID);
01589         lpMidiHdr->dwFlags |= MHDR_DONE;
01590         lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
01591 
01592         DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
01593                (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
01594                lpwm->mod.dwInstance, (DWORD_PTR)lpMidiHdr, 0);
01595         break;
01596     }
01597 
01598     for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = &(*lpmh)->lpNext);
01599     *lpmh = lpMidiHdr;
01600     lpMidiHdr = (LPMIDIHDR)msg->lParam;
01601     lpMidiHdr->lpNext = 0;
01602     lpMidiHdr->dwFlags |= MHDR_INQUEUE;
01603     lpMidiHdr->dwFlags &= ~MHDR_DONE;
01604     lpMidiHdr->dwOffset = 0;
01605 
01606     break;
01607     default:
01608     FIXME("Unknown message %d\n", msg->message);
01609     break;
01610     }
01611     return TRUE;
01612 }
01613 
01614 /**************************************************************************
01615  *              MMSYSTEM_MidiStream_Player  [internal]
01616  */
01617 static  DWORD   CALLBACK    MMSYSTEM_MidiStream_Player(LPVOID pmt)
01618 {
01619     WINE_MIDIStream*    lpMidiStrm = pmt;
01620     WINE_MIDI*      lpwm;
01621     MSG         msg;
01622     DWORD       dwToGo;
01623     DWORD       dwCurrTC;
01624     LPMIDIHDR       lpMidiHdr;
01625     LPMIDIEVENT     me;
01626     LPBYTE      lpData = 0;
01627 
01628     TRACE("(%p)!\n", lpMidiStrm);
01629 
01630     if (!lpMidiStrm ||
01631     (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL)
01632     goto the_end;
01633 
01634     /* force thread's queue creation */
01635     /* Used to be InitThreadInput16(0, 5); */
01636     /* but following works also with hack in midiStreamOpen */
01637     PeekMessageA(&msg, 0, 0, 0, 0);
01638 
01639     /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */
01640     SetEvent(lpMidiStrm->hEvent);
01641     TRACE("Ready to go 1\n");
01642     /* thread is started in paused mode */
01643     SuspendThread(lpMidiStrm->hThread);
01644     TRACE("Ready to go 2\n");
01645 
01646     lpMidiStrm->dwStartTicks = 0;
01647     lpMidiStrm->dwPulses = 0;
01648 
01649     lpMidiStrm->lpMidiHdr = 0;
01650 
01651     for (;;) {
01652     lpMidiHdr = lpMidiStrm->lpMidiHdr;
01653     if (!lpMidiHdr) {
01654         /* for first message, block until one arrives, then process all that are available */
01655         GetMessageA(&msg, 0, 0, 0);
01656         do {
01657         if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
01658             goto the_end;
01659         } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
01660         lpData = 0;
01661         continue;
01662     }
01663 
01664     if (!lpData)
01665         lpData = (LPBYTE)lpMidiHdr->lpData;
01666 
01667     me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset);
01668 
01669     /* do we have to wait ? */
01670     if (me->dwDeltaTime) {
01671         lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime);
01672         lpMidiStrm->dwPulses += me->dwDeltaTime;
01673 
01674         dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS;
01675 
01676         TRACE("%d/%d/%d\n", dwToGo, GetTickCount(), me->dwDeltaTime);
01677         while ((dwCurrTC = GetTickCount()) < dwToGo) {
01678         if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
01679             /* got a message, handle it */
01680             while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
01681             if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg))
01682                 goto the_end;
01683             }
01684             lpData = 0;
01685         } else {
01686             /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */
01687             break;
01688         }
01689         }
01690     }
01691     switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) {
01692     case MEVT_COMMENT:
01693         FIXME("NIY: MEVT_COMMENT\n");
01694         /* do nothing, skip bytes */
01695         break;
01696     case MEVT_LONGMSG:
01697         FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n");
01698         break;
01699     case MEVT_NOP:
01700         break;
01701     case MEVT_SHORTMSG:
01702         midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent));
01703         break;
01704     case MEVT_TEMPO:
01705         lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent);
01706         break;
01707     case MEVT_VERSION:
01708         break;
01709     default:
01710         FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK));
01711         break;
01712     }
01713     if (me->dwEvent & MEVT_F_CALLBACK) {
01714         DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
01715                (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB,
01716                lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L);
01717     }
01718     lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms);
01719     if (me->dwEvent & MEVT_F_LONG)
01720         lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3;
01721     if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) {
01722         /* done with this header */
01723         lpMidiHdr->dwFlags |= MHDR_DONE;
01724         lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
01725 
01726         lpMidiStrm->lpMidiHdr = lpMidiHdr->lpNext;
01727         DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags,
01728                (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE,
01729                lpwm->mod.dwInstance, (DWORD_PTR)lpMidiHdr, 0);
01730         lpData = 0;
01731     }
01732     }
01733 the_end:
01734     TRACE("End of thread\n");
01735     ExitThread(0);
01736     return 0;   /* for removing the warning, never executed */
01737 }
01738 
01739 /**************************************************************************
01740  *              MMSYSTEM_MidiStream_PostMessage [internal]
01741  */
01742 static  BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2)
01743 {
01744     if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) {
01745     //DWORD count;
01746 
01747     //ReleaseThunkLock(&count);
01748     WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
01749     //RestoreThunkLock(count);
01750     } else {
01751     WARN("bad PostThreadMessageA\n");
01752     return FALSE;
01753     }
01754     return TRUE;
01755 }
01756 
01757 /**************************************************************************
01758  *              midiStreamClose         [WINMM.@]
01759  */
01760 MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm)
01761 {
01762     WINE_MIDIStream*    lpMidiStrm;
01763 
01764     TRACE("(%p)!\n", hMidiStrm);
01765 
01766     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL))
01767     return MMSYSERR_INVALHANDLE;
01768 
01769     midiStreamStop(hMidiStrm);
01770     MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0);
01771     HeapFree(GetProcessHeap(), 0, lpMidiStrm);
01772     CloseHandle(lpMidiStrm->hEvent);
01773 
01774     return midiOutClose((HMIDIOUT)hMidiStrm);
01775 }
01776 
01777 /**************************************************************************
01778  *              midiStreamOpen          [WINMM.@]
01779  */
01780 MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
01781                    DWORD cMidi, DWORD_PTR dwCallback,
01782                    DWORD_PTR dwInstance, DWORD fdwOpen)
01783 {
01784     WINE_MIDIStream*    lpMidiStrm;
01785     MMRESULT        ret;
01786     MIDIOPENSTRMID  mosm;
01787     LPWINE_MIDI     lpwm;
01788     HMIDIOUT        hMidiOut;
01789 
01790     TRACE("(%p, %p, %d, 0x%08lx, 0x%08lx, 0x%08x)!\n",
01791       lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
01792 
01793     if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
01794     return MMSYSERR_INVALPARAM;
01795 
01796     lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
01797     if (!lpMidiStrm)
01798     return MMSYSERR_NOMEM;
01799 
01800     lpMidiStrm->dwTempo = 500000;
01801     lpMidiStrm->dwTimeDiv = 480;    /* 480 is 120 quarter notes per minute *//* FIXME ??*/
01802     lpMidiStrm->dwPositionMS = 0;
01803 
01804     mosm.dwStreamID = (DWORD_PTR)lpMidiStrm; // FIXME: not 64 bit safe
01805     /* FIXME: the correct value is not allocated yet for MAPPER */
01806     mosm.wDeviceID  = *lpuDeviceID;
01807     lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm);
01808     lpMidiStrm->hDevice = hMidiOut;
01809     if (lphMidiStrm)
01810     *lphMidiStrm = (HMIDISTRM)hMidiOut;
01811 
01812     lpwm->mld.uDeviceID = *lpuDeviceID;
01813 
01814     ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD_PTR)&lpwm->mod, fdwOpen);
01815     lpMidiStrm->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
01816     lpMidiStrm->wFlags = HIWORD(fdwOpen);
01817 
01818     lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player,
01819                        lpMidiStrm, 0, &(lpMidiStrm->dwThreadID));
01820 
01821     if (!lpMidiStrm->hThread) {
01822     midiStreamClose((HMIDISTRM)hMidiOut);
01823     return MMSYSERR_NOMEM;
01824     }
01825     SetThreadPriority(lpMidiStrm->hThread, THREAD_PRIORITY_TIME_CRITICAL);
01826 
01827     /* wait for thread to have started, and for its queue to be created */
01828     {
01829     //DWORD count;
01830 
01831     /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code,
01832      * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running
01833      * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue.
01834      */
01835     //ReleaseThunkLock(&count);
01836     WaitForSingleObject(lpMidiStrm->hEvent, INFINITE);
01837     //RestoreThunkLock(count);
01838     }
01839 
01840     TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n",
01841       *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm);
01842     return ret;
01843 }
01844 
01845 /**************************************************************************
01846  *              midiStreamOut           [WINMM.@]
01847  */
01848 MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
01849                   UINT cbMidiHdr)
01850 {
01851     WINE_MIDIStream*    lpMidiStrm;
01852     DWORD       ret = MMSYSERR_NOERROR;
01853 
01854     TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
01855 
01856     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
01857     ret = MMSYSERR_INVALHANDLE;
01858     } else if (!lpMidiHdr) {
01859         ret = MMSYSERR_INVALPARAM;
01860     } else {
01861     if (!PostThreadMessageA(lpMidiStrm->dwThreadID,
01862                                 WINE_MSM_HEADER, cbMidiHdr,
01863                                 (LPARAM)lpMidiHdr)) {
01864         WARN("bad PostThreadMessageA\n");
01865         ret = MMSYSERR_ERROR;
01866     }
01867     }
01868     return ret;
01869 }
01870 
01871 /**************************************************************************
01872  *              midiStreamPause         [WINMM.@]
01873  */
01874 MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm)
01875 {
01876     WINE_MIDIStream*    lpMidiStrm;
01877     DWORD       ret = MMSYSERR_NOERROR;
01878 
01879     TRACE("(%p)!\n", hMidiStrm);
01880 
01881     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
01882     ret = MMSYSERR_INVALHANDLE;
01883     } else {
01884     if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) {
01885         WARN("bad Suspend (%d)\n", GetLastError());
01886         ret = MMSYSERR_ERROR;
01887     }
01888     }
01889     return ret;
01890 }
01891 
01892 /**************************************************************************
01893  *              midiStreamPosition      [WINMM.@]
01894  */
01895 MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt)
01896 {
01897     WINE_MIDIStream*    lpMidiStrm;
01898     DWORD       ret = MMSYSERR_NOERROR;
01899 
01900     TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt);
01901 
01902     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
01903     ret = MMSYSERR_INVALHANDLE;
01904     } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) {
01905     ret = MMSYSERR_INVALPARAM;
01906     } else {
01907     switch (lpMMT->wType) {
01908     case TIME_MS:
01909         lpMMT->u.ms = lpMidiStrm->dwPositionMS;
01910         TRACE("=> %d ms\n", lpMMT->u.ms);
01911         break;
01912     case TIME_TICKS:
01913         lpMMT->u.ticks = lpMidiStrm->dwPulses;
01914         TRACE("=> %d ticks\n", lpMMT->u.ticks);
01915         break;
01916     default:
01917         WARN("Unsupported time type %d\n", lpMMT->wType);
01918         lpMMT->wType = TIME_MS;
01919         ret = MMSYSERR_INVALPARAM;
01920         break;
01921     }
01922     }
01923     return ret;
01924 }
01925 
01926 /**************************************************************************
01927  *              midiStreamProperty      [WINMM.@]
01928  */
01929 MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty)
01930 {
01931     WINE_MIDIStream*    lpMidiStrm;
01932     MMRESULT        ret = MMSYSERR_NOERROR;
01933 
01934     TRACE("(%p, %p, %x)\n", hMidiStrm, lpPropData, dwProperty);
01935 
01936     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
01937     ret = MMSYSERR_INVALHANDLE;
01938     } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) {
01939     ret = MMSYSERR_INVALPARAM;
01940     } else if (dwProperty & MIDIPROP_TEMPO) {
01941     MIDIPROPTEMPO*  mpt = (MIDIPROPTEMPO*)lpPropData;
01942 
01943     if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) {
01944         ret = MMSYSERR_INVALPARAM;
01945     } else if (dwProperty & MIDIPROP_SET) {
01946         lpMidiStrm->dwTempo = mpt->dwTempo;
01947         TRACE("Setting tempo to %d\n", mpt->dwTempo);
01948     } else if (dwProperty & MIDIPROP_GET) {
01949         mpt->dwTempo = lpMidiStrm->dwTempo;
01950         TRACE("Getting tempo <= %d\n", mpt->dwTempo);
01951     }
01952     } else if (dwProperty & MIDIPROP_TIMEDIV) {
01953     MIDIPROPTIMEDIV*    mptd = (MIDIPROPTIMEDIV*)lpPropData;
01954 
01955     if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) {
01956         ret = MMSYSERR_INVALPARAM;
01957     } else if (dwProperty & MIDIPROP_SET) {
01958         lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv;
01959         TRACE("Setting time div to %d\n", mptd->dwTimeDiv);
01960     } else if (dwProperty & MIDIPROP_GET) {
01961         mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv;
01962         TRACE("Getting time div <= %d\n", mptd->dwTimeDiv);
01963     }
01964     } else {
01965     ret = MMSYSERR_INVALPARAM;
01966     }
01967 
01968     return ret;
01969 }
01970 
01971 /**************************************************************************
01972  *              midiStreamRestart       [WINMM.@]
01973  */
01974 MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm)
01975 {
01976     WINE_MIDIStream*    lpMidiStrm;
01977     MMRESULT        ret = MMSYSERR_NOERROR;
01978 
01979     TRACE("(%p)!\n", hMidiStrm);
01980 
01981     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
01982     ret = MMSYSERR_INVALHANDLE;
01983     } else {
01984     DWORD   ret;
01985 
01986     /* since we increase the thread suspend count on each midiStreamPause
01987      * there may be a need for several midiStreamResume
01988      */
01989     do {
01990         ret = ResumeThread(lpMidiStrm->hThread);
01991     } while (ret != 0xFFFFFFFF && ret != 0);
01992     if (ret == 0xFFFFFFFF) {
01993         WARN("bad Resume (%d)\n", GetLastError());
01994         ret = MMSYSERR_ERROR;
01995     } else {
01996         lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS;
01997     }
01998     }
01999     return ret;
02000 }
02001 
02002 /**************************************************************************
02003  *              midiStreamStop          [WINMM.@]
02004  */
02005 MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm)
02006 {
02007     WINE_MIDIStream*    lpMidiStrm;
02008     MMRESULT        ret = MMSYSERR_NOERROR;
02009 
02010     TRACE("(%p)!\n", hMidiStrm);
02011 
02012     if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) {
02013     ret = MMSYSERR_INVALHANDLE;
02014     } else {
02015     /* in case stream has been paused... FIXME is the current state correct ? */
02016     midiStreamRestart(hMidiStrm);
02017     MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0);
02018     }
02019     return ret;
02020 }
02021 
02022 static UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType,
02023                       LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
02024                       DWORD_PTR dwInstance, DWORD dwFlags)
02025 {
02026     HANDLE      handle;
02027     LPWINE_MLD      wmld;
02028     DWORD       dwRet = MMSYSERR_NOERROR;
02029     WAVEOPENDESC    wod;
02030 
02031     TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08X);\n",
02032       lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
02033       dwInstance, dwFlags);
02034 
02035     if (dwFlags & WAVE_FORMAT_QUERY)
02036         TRACE("WAVE_FORMAT_QUERY requested !\n");
02037 
02038     if (lpFormat == NULL) {
02039         WARN("bad format\n");
02040         return WAVERR_BADFORMAT;
02041     }
02042 
02043     if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1)) {
02044         WARN("invalid parameter\n");
02045     return MMSYSERR_INVALPARAM;
02046     }
02047 
02048     /* may have a PCMWAVEFORMAT rather than a WAVEFORMATEX so don't read cbSize */
02049     TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u\n",
02050       lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
02051       lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample);
02052 
02053     if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
02054                 &dwFlags, &dwCallback, &dwInstance)) == NULL) {
02055         WARN("no memory\n");
02056     return MMSYSERR_NOMEM;
02057     }
02058 
02059     wod.hWave = handle;
02060     wod.lpFormat = (LPWAVEFORMATEX)lpFormat;  /* should the struct be copied iso pointer? */
02061     wod.dwCallback = dwCallback;
02062     wod.dwInstance = dwInstance;
02063     wod.dnDevNode = 0L;
02064 
02065     TRACE("cb=%08lx\n", wod.dwCallback);
02066 
02067     for (;;) {
02068         if (dwFlags & WAVE_MAPPED) {
02069             wod.uMappedDeviceID = uDeviceID;
02070             uDeviceID = WAVE_MAPPER;
02071         } else {
02072             wod.uMappedDeviceID = -1;
02073         }
02074         wmld->uDeviceID = uDeviceID;
02075     
02076         dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN,
02077                            (DWORD_PTR)&wod, dwFlags);
02078 
02079         TRACE("dwRet = %s\n", WINMM_ErrorToString(dwRet));
02080         if (dwRet != WAVERR_BADFORMAT ||
02081             ((dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) || (uDeviceID == WAVE_MAPPER)) break;
02082         /* if we ask for a format which isn't supported by the physical driver, 
02083          * let's try to map it through the wave mapper (except, if we already tried
02084          * or user didn't allow us to use acm codecs or the device is already the mapper)
02085          */
02086         dwFlags |= WAVE_MAPPED;
02087         /* we shall loop only one */
02088     }
02089 
02090     if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
02091         MMDRV_Free(handle, wmld);
02092         handle = 0;
02093     }
02094 
02095     if (lphndl != NULL) *lphndl = handle;
02096     TRACE("=> %s hWave=%p\n", WINMM_ErrorToString(dwRet), handle);
02097 
02098     return dwRet;
02099 }
02100 
02101 /**************************************************************************
02102  *              waveOutGetNumDevs       [WINMM.@]
02103  */
02104 UINT WINAPI waveOutGetNumDevs(void)
02105 {
02106     return MMDRV_GetNum(MMDRV_WAVEOUT);
02107 }
02108 
02109 /**************************************************************************
02110  *              waveOutGetDevCapsA      [WINMM.@]
02111  */
02112 UINT WINAPI waveOutGetDevCapsA(UINT_PTR uDeviceID, LPWAVEOUTCAPSA lpCaps,
02113                    UINT uSize)
02114 {
02115     WAVEOUTCAPSW    wocW;
02116     UINT        ret;
02117 
02118     if (lpCaps == NULL)        return MMSYSERR_INVALPARAM;
02119 
02120     ret = waveOutGetDevCapsW(uDeviceID, &wocW, sizeof(wocW));
02121 
02122     if (ret == MMSYSERR_NOERROR) {
02123     WAVEOUTCAPSA wocA;
02124     wocA.wMid           = wocW.wMid;
02125     wocA.wPid           = wocW.wPid;
02126     wocA.vDriverVersion = wocW.vDriverVersion;
02127         WideCharToMultiByte( CP_ACP, 0, wocW.szPname, -1, wocA.szPname,
02128                              sizeof(wocA.szPname), NULL, NULL );
02129     wocA.dwFormats      = wocW.dwFormats;
02130     wocA.wChannels      = wocW.wChannels;
02131     wocA.dwSupport      = wocW.dwSupport;
02132     memcpy(lpCaps, &wocA, min(uSize, sizeof(wocA)));
02133     }
02134     return ret;
02135 }
02136 
02137 /**************************************************************************
02138  *              waveOutGetDevCapsW      [WINMM.@]
02139  */
02140 UINT WINAPI waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps,
02141                    UINT uSize)
02142 {
02143     LPWINE_MLD      wmld;
02144 
02145     TRACE("(%lu %p %u)!\n", uDeviceID, lpCaps, uSize);
02146 
02147     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
02148 
02149     if (uDeviceID == WAVE_MAPPER)
02150     {
02151         FIXME("Support WAVE_MAPPER\n");
02152         uDeviceID = 0;
02153     }
02154 
02155     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
02156         return MMSYSERR_BADDEVICEID;
02157 
02158     return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize);
02159 }
02160 
02161 /**************************************************************************
02162  *              waveOutGetErrorTextA    [WINMM.@]
02163  *              waveInGetErrorTextA     [WINMM.@]
02164  */
02165 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
02166 {
02167     UINT    ret;
02168 
02169     if (lpText == NULL) ret = MMSYSERR_INVALPARAM;
02170     else if (uSize == 0) ret = MMSYSERR_NOERROR;
02171     else
02172     {
02173         LPWSTR  xstr = HeapAlloc(GetProcessHeap(), 0, uSize * sizeof(WCHAR));
02174         if (!xstr) ret = MMSYSERR_NOMEM;
02175         else
02176         {
02177             ret = waveOutGetErrorTextW(uError, xstr, uSize);
02178             if (ret == MMSYSERR_NOERROR)
02179                 WideCharToMultiByte(CP_ACP, 0, xstr, -1, lpText, uSize, NULL, NULL);
02180             HeapFree(GetProcessHeap(), 0, xstr);
02181         }
02182     }
02183     return ret;
02184 }
02185 
02186 /**************************************************************************
02187  *              waveOutGetErrorTextW    [WINMM.@]
02188  *              waveInGetErrorTextW     [WINMM.@]
02189  */
02190 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
02191 {
02192     UINT        ret = MMSYSERR_BADERRNUM;
02193 
02194     if (lpText == NULL) ret = MMSYSERR_INVALPARAM;
02195     else if (uSize == 0) ret = MMSYSERR_NOERROR;
02196     else if (
02197            /* test has been removed because MMSYSERR_BASE is 0, and gcc did emit
02198         * a warning for the test was always true */
02199            (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
02200            (uError >= WAVERR_BASE  && uError <= WAVERR_LASTERROR)) {
02201     if (LoadStringW(hWinMM32Instance,
02202             uError, lpText, uSize) > 0) {
02203         ret = MMSYSERR_NOERROR;
02204     }
02205     }
02206     return ret;
02207 }
02208 
02209 /**************************************************************************
02210  *          waveOutOpen         [WINMM.@]
02211  * All the args/structs have the same layout as the win16 equivalents
02212  */
02213 MMRESULT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID,
02214                        LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
02215                        DWORD_PTR dwInstance, DWORD dwFlags)
02216 {
02217     return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
02218                      dwCallback, dwInstance, dwFlags);
02219 }
02220 
02221 /**************************************************************************
02222  *              waveOutClose        [WINMM.@]
02223  */
02224 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
02225 {
02226     LPWINE_MLD      wmld;
02227     DWORD       dwRet;
02228 
02229     TRACE("(%p)\n", hWaveOut);
02230 
02231     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
02232     return MMSYSERR_INVALHANDLE;
02233 
02234     dwRet = MMDRV_Close(wmld, WODM_CLOSE);
02235     if (dwRet != WAVERR_STILLPLAYING)
02236     MMDRV_Free(hWaveOut, wmld);
02237 
02238     return dwRet;
02239 }
02240 
02241 /**************************************************************************
02242  *              waveOutPrepareHeader    [WINMM.@]
02243  */
02244 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
02245                  WAVEHDR* lpWaveOutHdr, UINT uSize)
02246 {
02247     LPWINE_MLD      wmld;
02248     UINT        result;
02249 
02250     TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
02251 
02252     if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR))
02253     return MMSYSERR_INVALPARAM;
02254 
02255     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
02256     return MMSYSERR_INVALHANDLE;
02257 
02258     if ((result = MMDRV_Message(wmld, WODM_PREPARE, (DWORD_PTR)lpWaveOutHdr,
02259                                 uSize)) != MMSYSERR_NOTSUPPORTED)
02260         return result;
02261 
02262     if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
02263     return WAVERR_STILLPLAYING;
02264 
02265     lpWaveOutHdr->dwFlags |= WHDR_PREPARED;
02266     lpWaveOutHdr->dwFlags &= ~WHDR_DONE;
02267 
02268     return MMSYSERR_NOERROR;
02269 }
02270 
02271 /**************************************************************************
02272  *              waveOutUnprepareHeader  [WINMM.@]
02273  */
02274 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
02275                    LPWAVEHDR lpWaveOutHdr, UINT uSize)
02276 {
02277     LPWINE_MLD      wmld;
02278     UINT        result;
02279 
02280     TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
02281 
02282     if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR))
02283     return MMSYSERR_INVALPARAM;
02284     
02285     if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
02286     return MMSYSERR_NOERROR;
02287     }
02288 
02289     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
02290     return MMSYSERR_INVALHANDLE;
02291 
02292     if ((result = MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD_PTR)lpWaveOutHdr,
02293                                 uSize)) != MMSYSERR_NOTSUPPORTED)
02294         return result;
02295 
02296     if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
02297     return WAVERR_STILLPLAYING;
02298 
02299     lpWaveOutHdr->dwFlags &= ~WHDR_PREPARED;
02300     lpWaveOutHdr->dwFlags |= WHDR_DONE;
02301 
02302     return MMSYSERR_NOERROR;
02303 }
02304 
02305 /**************************************************************************
02306  *              waveOutWrite        [WINMM.@]
02307  */
02308 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
02309              UINT uSize)
02310 {
02311     LPWINE_MLD      wmld;
02312 
02313     TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
02314 
02315     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
02316     return MMSYSERR_INVALHANDLE;
02317 
02318     return MMDRV_Message(wmld, WODM_WRITE, (DWORD_PTR)lpWaveOutHdr, uSize);
02319 }
02320 
02321 /**************************************************************************
02322  *              waveOutBreakLoop    [WINMM.@]
02323  */
02324 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
02325 {
02326     LPWINE_MLD      wmld;
02327 
02328     TRACE("(%p);\n", hWaveOut);
02329 
02330     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
02331         return MMSYSERR_INVALHANDLE;
02332     return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L);
02333 }
02334 
02335 /**************************************************************************
02336  *              waveOutPause        [WINMM.@]
02337  */
02338 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
02339 {
02340     LPWINE_MLD      wmld;
02341 
02342     TRACE("(%p);\n", hWaveOut);
02343 
02344     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
02345         return MMSYSERR_INVALHANDLE;
02346     return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L);
02347 }
02348 
02349 /**************************************************************************
02350  *              waveOutReset        [WINMM.@]
02351  */
02352 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
02353 {
02354     LPWINE_MLD      wmld;
02355 
02356     TRACE("(%p);\n", hWaveOut);
02357 
02358     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
02359         return MMSYSERR_INVALHANDLE;
02360     return MMDRV_Message(wmld, WODM_RESET, 0L, 0L);
02361 }
02362 
02363 /**************************************************************************
02364  *              waveOutRestart      [WINMM.@]
02365  */
02366 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
02367 {
02368     LPWINE_MLD      wmld;
02369 
02370     TRACE("(%p);\n", hWaveOut);
02371 
02372     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
02373         return MMSYSERR_INVALHANDLE;
02374     return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L);
02375 }
02376 
02377 /**************************************************************************
02378  *              waveOutGetPosition  [WINMM.@]
02379  */
02380 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
02381                    UINT uSize)
02382 {
02383     LPWINE_MLD      wmld;
02384 
02385     TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize);
02386 
02387     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
02388     return MMSYSERR_INVALHANDLE;
02389 
02390     return MMDRV_Message(wmld, WODM_GETPOS, (DWORD_PTR)lpTime, uSize);
02391 }
02392 
02393 /**************************************************************************
02394  *              waveOutGetPitch     [WINMM.@]
02395  */
02396 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
02397 {
02398     LPWINE_MLD      wmld;
02399 
02400     TRACE("(%p, %p);\n", hWaveOut, lpdw);
02401 
02402     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
02403         return MMSYSERR_INVALHANDLE;
02404     return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD_PTR)lpdw, 0L);
02405 }
02406 
02407 /**************************************************************************
02408  *              waveOutSetPitch     [WINMM.@]
02409  */
02410 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
02411 {
02412     LPWINE_MLD      wmld;
02413 
02414     TRACE("(%p, %08x);\n", hWaveOut, dw);
02415 
02416     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
02417         return MMSYSERR_INVALHANDLE;
02418     return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L);
02419 }
02420 
02421 /**************************************************************************
02422  *              waveOutGetPlaybackRate  [WINMM.@]
02423  */
02424 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
02425 {
02426     LPWINE_MLD      wmld;
02427 
02428     TRACE("(%p, %p);\n", hWaveOut, lpdw);
02429 
02430     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
02431         return MMSYSERR_INVALHANDLE;
02432     return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD_PTR)lpdw, 0L);
02433 }
02434 
02435 /**************************************************************************
02436  *              waveOutSetPlaybackRate  [WINMM.@]
02437  */
02438 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
02439 {
02440     LPWINE_MLD      wmld;
02441 
02442     TRACE("(%p, %08x);\n", hWaveOut, dw);
02443 
02444     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
02445         return MMSYSERR_INVALHANDLE;
02446     return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L);
02447 }
02448 
02449 /**************************************************************************
02450  *              waveOutGetVolume    [WINMM.@]
02451  */
02452 UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw)
02453 {
02454     LPWINE_MLD      wmld;
02455 
02456     TRACE("(%p, %p);\n", hWaveOut, lpdw);
02457 
02458     if (lpdw == NULL) {
02459         WARN("invalid parameter\n");
02460         return MMSYSERR_INVALPARAM;
02461     }
02462 
02463     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
02464         return MMSYSERR_INVALHANDLE;
02465 
02466     return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD_PTR)lpdw, 0L);
02467 }
02468 
02469 /**************************************************************************
02470  *              waveOutSetVolume    [WINMM.@]
02471  */
02472 UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw)
02473 {
02474     LPWINE_MLD      wmld;
02475 
02476     TRACE("(%p, %08x);\n", hWaveOut, dw);
02477 
02478      if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
02479         return MMSYSERR_INVALHANDLE;
02480 
02481     return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L);
02482 }
02483 
02484 /**************************************************************************
02485  *              waveOutGetID        [WINMM.@]
02486  */
02487 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
02488 {
02489     LPWINE_MLD      wmld;
02490 
02491     TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID);
02492 
02493     if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
02494 
02495     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
02496     return MMSYSERR_INVALHANDLE;
02497 
02498     *lpuDeviceID = wmld->uDeviceID;
02499     return 0;
02500 }
02501 
02502 /**************************************************************************
02503  *              waveOutMessage      [WINMM.@]
02504  */
02505 UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
02506                            DWORD_PTR dwParam1, DWORD_PTR dwParam2)
02507 {
02508     LPWINE_MLD      wmld;
02509 
02510     TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
02511 
02512     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
02513     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
02514         return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
02515     }
02516         WARN("invalid handle\n");
02517     return MMSYSERR_INVALHANDLE;
02518     }
02519 
02520     /* from M$ KB */
02521     if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) {
02522         WARN("invalid parameter\n");
02523     return MMSYSERR_INVALPARAM;
02524     }
02525 
02526     return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2);
02527 }
02528 
02529 /**************************************************************************
02530  *              waveInGetNumDevs        [WINMM.@]
02531  */
02532 UINT WINAPI waveInGetNumDevs(void)
02533 {
02534     return MMDRV_GetNum(MMDRV_WAVEIN);
02535 }
02536 
02537 /**************************************************************************
02538  *              waveInGetDevCapsW       [WINMM.@]
02539  */
02540 UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
02541 {
02542     LPWINE_MLD      wmld;
02543 
02544     TRACE("(%lu %p %u)!\n", uDeviceID, lpCaps, uSize);
02545 
02546     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
02547 
02548     if (uDeviceID == WAVE_MAPPER)
02549     {
02550         FIXME("Support WAVE_MAPPER\n");
02551         uDeviceID = 0;
02552     }
02553 
02554 
02555     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
02556     return MMSYSERR_BADDEVICEID;
02557 
02558     return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize);
02559 }
02560 
02561 /**************************************************************************
02562  *              waveInGetDevCapsA       [WINMM.@]
02563  */
02564 UINT WINAPI waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
02565 {
02566     WAVEINCAPSW     wicW;
02567     UINT        ret;
02568 
02569     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
02570 
02571     ret = waveInGetDevCapsW(uDeviceID, &wicW, sizeof(wicW));
02572 
02573     if (ret == MMSYSERR_NOERROR) {
02574     WAVEINCAPSA wicA;
02575     wicA.wMid           = wicW.wMid;
02576     wicA.wPid           = wicW.wPid;
02577     wicA.vDriverVersion = wicW.vDriverVersion;
02578         WideCharToMultiByte( CP_ACP, 0, wicW.szPname, -1, wicA.szPname,
02579                              sizeof(wicA.szPname), NULL, NULL );
02580     wicA.dwFormats      = wicW.dwFormats;
02581     wicA.wChannels      = wicW.wChannels;
02582     memcpy(lpCaps, &wicA, min(uSize, sizeof(wicA)));
02583     }
02584     return ret;
02585 }
02586 
02587 /**************************************************************************
02588  *              waveInOpen          [WINMM.@]
02589  */
02590 MMRESULT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
02591                            LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
02592                            DWORD_PTR dwInstance, DWORD dwFlags)
02593 {
02594     return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
02595                      dwCallback, dwInstance, dwFlags);
02596 }
02597 
02598 /**************************************************************************
02599  *              waveInClose         [WINMM.@]
02600  */
02601 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
02602 {
02603     LPWINE_MLD      wmld;
02604     DWORD       dwRet;
02605 
02606     TRACE("(%p)\n", hWaveIn);
02607 
02608     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
02609     return MMSYSERR_INVALHANDLE;
02610 
02611     dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L);
02612     if (dwRet != WAVERR_STILLPLAYING)
02613     MMDRV_Free(hWaveIn, wmld);
02614     return dwRet;
02615 }
02616 
02617 /**************************************************************************
02618  *              waveInPrepareHeader     [WINMM.@]
02619  */
02620 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
02621                 UINT uSize)
02622 {
02623     LPWINE_MLD      wmld;
02624     UINT                result;
02625 
02626     TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
02627 
02628     if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR))
02629     return MMSYSERR_INVALPARAM;
02630 
02631     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
02632     return MMSYSERR_INVALHANDLE;
02633 
02634     if ((result = MMDRV_Message(wmld, WIDM_PREPARE, (DWORD_PTR)lpWaveInHdr,
02635                                 uSize)) != MMSYSERR_NOTSUPPORTED)
02636         return result;
02637 
02638     if (lpWaveInHdr->dwFlags & WHDR_INQUEUE)
02639         return WAVERR_STILLPLAYING;
02640 
02641     lpWaveInHdr->dwFlags |= WHDR_PREPARED;
02642     lpWaveInHdr->dwFlags &= ~WHDR_DONE;
02643     lpWaveInHdr->dwBytesRecorded = 0;
02644 
02645     return MMSYSERR_NOERROR;
02646 }
02647 
02648 /**************************************************************************
02649  *              waveInUnprepareHeader   [WINMM.@]
02650  */
02651 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
02652                   UINT uSize)
02653 {
02654     LPWINE_MLD      wmld;
02655     UINT                result;
02656 
02657     TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
02658 
02659     if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR))
02660     return MMSYSERR_INVALPARAM;
02661 
02662     if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED))
02663     return MMSYSERR_NOERROR;
02664 
02665     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
02666     return MMSYSERR_INVALHANDLE;
02667 
02668     if ((result = MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD_PTR)lpWaveInHdr,
02669                                 uSize)) != MMSYSERR_NOTSUPPORTED)
02670         return result;
02671 
02672     if (lpWaveInHdr->dwFlags & WHDR_INQUEUE)
02673         return WAVERR_STILLPLAYING;
02674 
02675     lpWaveInHdr->dwFlags &= ~WHDR_PREPARED;
02676     lpWaveInHdr->dwFlags |= WHDR_DONE;
02677 
02678     return MMSYSERR_NOERROR;
02679 }
02680 
02681 /**************************************************************************
02682  *              waveInAddBuffer     [WINMM.@]
02683  */
02684 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
02685                 WAVEHDR* lpWaveInHdr, UINT uSize)
02686 {
02687     LPWINE_MLD      wmld;
02688 
02689     TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
02690 
02691     if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
02692     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
02693     return MMSYSERR_INVALHANDLE;
02694 
02695     return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD_PTR)lpWaveInHdr, uSize);
02696 }
02697 
02698 /**************************************************************************
02699  *              waveInReset     [WINMM.@]
02700  */
02701 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
02702 {
02703     LPWINE_MLD      wmld;
02704 
02705     TRACE("(%p);\n", hWaveIn);
02706 
02707     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
02708     return MMSYSERR_INVALHANDLE;
02709 
02710     return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L);
02711 }
02712 
02713 /**************************************************************************
02714  *              waveInStart     [WINMM.@]
02715  */
02716 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
02717 {
02718     LPWINE_MLD      wmld;
02719 
02720     TRACE("(%p);\n", hWaveIn);
02721 
02722     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
02723     return MMSYSERR_INVALHANDLE;
02724 
02725     return MMDRV_Message(wmld, WIDM_START, 0L, 0L);
02726 }
02727 
02728 /**************************************************************************
02729  *              waveInStop      [WINMM.@]
02730  */
02731 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
02732 {
02733     LPWINE_MLD      wmld;
02734 
02735     TRACE("(%p);\n", hWaveIn);
02736 
02737     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
02738     return MMSYSERR_INVALHANDLE;
02739 
02740     return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L);
02741 }
02742 
02743 /**************************************************************************
02744  *              waveInGetPosition   [WINMM.@]
02745  */
02746 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
02747                   UINT uSize)
02748 {
02749     LPWINE_MLD      wmld;
02750 
02751     TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize);
02752 
02753     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
02754     return MMSYSERR_INVALHANDLE;
02755 
02756     return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD_PTR)lpTime, uSize);
02757 }
02758 
02759 /**************************************************************************
02760  *              waveInGetID         [WINMM.@]
02761  */
02762 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
02763 {
02764     LPWINE_MLD      wmld;
02765 
02766     TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID);
02767 
02768     if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
02769 
02770     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
02771     return MMSYSERR_INVALHANDLE;
02772 
02773     *lpuDeviceID = wmld->uDeviceID;
02774     return MMSYSERR_NOERROR;
02775 }
02776 
02777 /**************************************************************************
02778  *              waveInMessage       [WINMM.@]
02779  */
02780 UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
02781                           DWORD_PTR dwParam1, DWORD_PTR dwParam2)
02782 {
02783     LPWINE_MLD      wmld;
02784 
02785     TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
02786 
02787     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) {
02788     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) {
02789         return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
02790     }
02791     return MMSYSERR_INVALHANDLE;
02792     }
02793 
02794     /* from M$ KB */
02795     if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
02796     return MMSYSERR_INVALPARAM;
02797 
02798 
02799     return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2);
02800 }
02801 
02802 struct mm_starter
02803 {
02804     LPTASKCALLBACK      cb;
02805     DWORD               client;
02806     HANDLE              event;
02807 };
02808 
02809 static DWORD WINAPI mmTaskRun(void* pmt)
02810 {
02811     struct mm_starter mms;
02812 
02813     memcpy(&mms, pmt, sizeof(struct mm_starter));
02814     HeapFree(GetProcessHeap(), 0, pmt);
02815     mms.cb(mms.client);
02816     if (mms.event) SetEvent(mms.event);
02817     return 0;
02818 }
02819 
02820 /******************************************************************
02821  *      mmTaskCreate (WINMM.@)
02822  */
02823 UINT     WINAPI mmTaskCreate(LPTASKCALLBACK cb, HANDLE* ph, DWORD_PTR client)
02824 {
02825     HANDLE               hThread;
02826     HANDLE               hEvent = 0;
02827     struct mm_starter   *mms;
02828 
02829     mms = HeapAlloc(GetProcessHeap(), 0, sizeof(struct mm_starter));
02830     if (mms == NULL) return TASKERR_OUTOFMEMORY;
02831 
02832     mms->cb = cb;
02833     mms->client = client;
02834     if (ph) hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
02835     mms->event = hEvent;
02836 
02837     hThread = CreateThread(0, 0, mmTaskRun, mms, 0, NULL);
02838     if (!hThread) {
02839         HeapFree(GetProcessHeap(), 0, mms);
02840         if (hEvent) CloseHandle(hEvent);
02841         return TASKERR_OUTOFMEMORY;
02842     }
02843     SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
02844     if (ph) *ph = hEvent;
02845     CloseHandle(hThread);
02846     return 0;
02847 }
02848 
02849 /******************************************************************
02850  *      mmTaskBlock (WINMM.@)
02851  */
02852 VOID     WINAPI mmTaskBlock(DWORD tid)
02853 {
02854     MSG     msg;
02855 
02856     do
02857     {
02858     GetMessageA(&msg, 0, 0, 0);
02859     if (msg.hwnd) DispatchMessageA(&msg);
02860     } while (msg.message != WM_USER);
02861 }
02862 
02863 /******************************************************************
02864  *      mmTaskSignal (WINMM.@)
02865  */
02866 BOOL     WINAPI mmTaskSignal(DWORD tid)
02867 {
02868     return PostThreadMessageW(tid, WM_USER, 0, 0);
02869 }
02870 
02871 /******************************************************************
02872  *      mmTaskYield (WINMM.@)
02873  */
02874 VOID     WINAPI mmTaskYield(VOID) {}
02875 
02876 /******************************************************************
02877  *      mmGetCurrentTask (WINMM.@)
02878  */
02879 DWORD    WINAPI mmGetCurrentTask(VOID)
02880 {
02881     return GetCurrentThreadId();
02882 }

Generated on Sun May 27 2012 04:26:59 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.