From 7010fa377f9b7d6668510a87a0423fb620b709f2 Mon Sep 17 00:00:00 2001 From: Andrew Greenwood Date: Fri, 22 Aug 2003 14:56:59 +0000 Subject: [PATCH] * Started porting WINMM from WINE * Defined __WINE_FOR_REACTOS__ and created internal.h, which defines a few things not already defined. It compiles, but *will NOT* link, as I haven't finished porting yet. I'll continue hacking away at it. svn path=/trunk/; revision=5756 --- reactos/apps/tests/button/btntest.sym | Bin 0 -> 16 bytes reactos/include/mmddk.h | 445 ++++ reactos/include/wine/windef16.h | 146 ++ reactos/lib/winmm/Makefile | 10 +- reactos/lib/winmm/driver.c | 543 +++++ reactos/lib/winmm/internal.h | 26 + reactos/lib/winmm/lolvldrv.c | 837 +++++++ reactos/lib/winmm/midiin.c | 164 -- reactos/lib/winmm/mmsystem16.h | 808 +++++++ reactos/lib/winmm/winemm.h | 351 +++ reactos/lib/winmm/winmm.c | 2881 +++++++++++++++++++++++++ reactos/lib/winmm/winmm.rc | 2 +- 12 files changed, 6042 insertions(+), 171 deletions(-) create mode 100644 reactos/apps/tests/button/btntest.sym create mode 100644 reactos/include/mmddk.h create mode 100644 reactos/include/wine/windef16.h create mode 100644 reactos/lib/winmm/driver.c create mode 100644 reactos/lib/winmm/internal.h create mode 100644 reactos/lib/winmm/lolvldrv.c delete mode 100644 reactos/lib/winmm/midiin.c create mode 100644 reactos/lib/winmm/mmsystem16.h create mode 100644 reactos/lib/winmm/winemm.h create mode 100644 reactos/lib/winmm/winmm.c diff --git a/reactos/apps/tests/button/btntest.sym b/reactos/apps/tests/button/btntest.sym new file mode 100644 index 0000000000000000000000000000000000000000..be1e4f7e07082655b249554e165d4564e66c9eef GIT binary patch literal 16 NcmWe&fB*p~4FCa<03iSX literal 0 HcmV?d00001 diff --git a/reactos/include/mmddk.h b/reactos/include/mmddk.h new file mode 100644 index 00000000000..46912451524 --- /dev/null +++ b/reactos/include/mmddk.h @@ -0,0 +1,445 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/***************************************************************************** + * Copyright 1998, Luiz Otavio L. Zorzella + * 1999, Eric Pouech + * + * Purpose: multimedia declarations (external to WINMM & MMSYSTEM DLLs + * for other DLLs (MCI, drivers...)) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ***************************************************************************** + */ +#ifndef __MMDDK_H +#define __MMDDK_H + +#include "mmsystem.h" +//#include "winbase.h" + +#define MAX_MIDIINDRV (16) +/* For now I'm making 16 the maximum number of midi devices one can + * have. This should be more than enough for everybody. But as a purist, + * I intend to make it unbounded in the future, as soon as I figure + * a good way to do so. + */ +#define MAX_MIDIOUTDRV (16) + +/* ================================== + * Multimedia DDK compatible part + * ================================== */ + +#include "pshpack1.h" + +#define DRVM_INIT 100 +#define DRVM_EXIT 101 +#define DRVM_DISABLE 102 +#define DRVM_ENABLE 103 + +/* messages that have IOCTL format + * dw1 = NULL or handle + * dw2 = NULL or ptr to DRVM_IOCTL_DATA + * return is MMRESULT + */ +#define DRVM_IOCTL 0x100 +#define DRVM_ADD_THRU (DRVM_IOCTL+1) +#define DRVM_REMOVE_THRU (DRVM_IOCTL+2) +#define DRVM_IOCTL_LAST (DRVM_IOCTL+5) +typedef struct { + DWORD dwSize; /* size of this structure */ + DWORD dwCmd; /* IOCTL command code, 0x80000000 and above reserved for system */ +} DRVM_IOCTL_DATA, *LPDRVM_IOCTL_DATA; + +/* command code ranges for dwCmd field of DRVM_IOCTL message + * - codes from 0 to 0x7FFFFFFF are user defined + * - codes from 0x80000000 to 0xFFFFFFFF are reserved for future definition by microsoft + */ +#define DRVM_IOCTL_CMD_USER 0x00000000L +#define DRVM_IOCTL_CMD_SYSTEM 0x80000000L + +#define DRVM_MAPPER 0x2000 +#define DRVM_USER 0x4000 +#define DRVM_MAPPER_STATUS (DRVM_MAPPER+0) +#define DRVM_MAPPER_RECONFIGURE (DRVM_MAPPER+1) + +#define DRV_QUERYDRVENTRY (DRV_RESERVED + 1) +#define DRV_QUERYDEVNODE (DRV_RESERVED + 2) +#define DRV_QUERYNAME (DRV_RESERVED + 3) +#define DRV_QUERYDRIVERIDS (DRV_RESERVED + 4) +#define DRV_QUERYMAPPABLE (DRV_RESERVED + 5) +#ifdef __WINESRC__ +#define DRV_QUERYDSOUNDIFACE (DRV_RESERVED + 10) +#define DRV_QUERYDSOUNDDESC (DRV_RESERVED + 11) +#define DRV_QUERYDSOUNDGUID (DRV_RESERVED + 12) +#endif + +#define WODM_INIT DRVM_INIT +#define WODM_GETNUMDEVS 3 +#define WODM_GETDEVCAPS 4 +#define WODM_OPEN 5 +#define WODM_CLOSE 6 +#define WODM_PREPARE 7 +#define WODM_UNPREPARE 8 +#define WODM_WRITE 9 +#define WODM_PAUSE 10 +#define WODM_RESTART 11 +#define WODM_RESET 12 +#define WODM_GETPOS 13 +#define WODM_GETPITCH 14 +#define WODM_SETPITCH 15 +#define WODM_GETVOLUME 16 +#define WODM_SETVOLUME 17 +#define WODM_GETPLAYBACKRATE 18 +#define WODM_SETPLAYBACKRATE 19 +#define WODM_BREAKLOOP 20 + +#define WODM_MAPPER_STATUS (DRVM_MAPPER_STATUS + 0) +#define WAVEOUT_MAPPER_STATUS_DEVICE 0 +#define WAVEOUT_MAPPER_STATUS_MAPPED 1 +#define WAVEOUT_MAPPER_STATUS_FORMAT 2 + +#define WIDM_INIT DRVM_INIT +#define WIDM_GETNUMDEVS 50 +#define WIDM_GETDEVCAPS 51 +#define WIDM_OPEN 52 +#define WIDM_CLOSE 53 +#define WIDM_PREPARE 54 +#define WIDM_UNPREPARE 55 +#define WIDM_ADDBUFFER 56 +#define WIDM_START 57 +#define WIDM_STOP 58 +#define WIDM_RESET 59 +#define WIDM_GETPOS 60 + +#define WIDM_MAPPER_STATUS (DRVM_MAPPER_STATUS + 0) +#define WAVEIN_MAPPER_STATUS_DEVICE 0 +#define WAVEIN_MAPPER_STATUS_MAPPED 1 +#define WAVEIN_MAPPER_STATUS_FORMAT 2 + +#define MODM_INIT DRVM_INIT +#define MODM_GETNUMDEVS 1 +#define MODM_GETDEVCAPS 2 +#define MODM_OPEN 3 +#define MODM_CLOSE 4 +#define MODM_PREPARE 5 +#define MODM_UNPREPARE 6 +#define MODM_DATA 7 +#define MODM_LONGDATA 8 +#define MODM_RESET 9 +#define MODM_GETVOLUME 10 +#define MODM_SETVOLUME 11 +#define MODM_CACHEPATCHES 12 +#define MODM_CACHEDRUMPATCHES 13 + +#define MIDM_INIT DRVM_INIT +#define MIDM_GETNUMDEVS 53 +#define MIDM_GETDEVCAPS 54 +#define MIDM_OPEN 55 +#define MIDM_CLOSE 56 +#define MIDM_PREPARE 57 +#define MIDM_UNPREPARE 58 +#define MIDM_ADDBUFFER 59 +#define MIDM_START 60 +#define MIDM_STOP 61 +#define MIDM_RESET 62 + + +#define AUXM_INIT DRVM_INIT +#define AUXDM_GETNUMDEVS 3 +#define AUXDM_GETDEVCAPS 4 +#define AUXDM_GETVOLUME 5 +#define AUXDM_SETVOLUME 6 + +#define MXDM_INIT DRVM_INIT +#define MXDM_USER DRVM_USER +#define MXDM_MAPPER DRVM_MAPPER + +#define MXDM_GETNUMDEVS 1 +#define MXDM_GETDEVCAPS 2 +#define MXDM_OPEN 3 +#define MXDM_CLOSE 4 +#define MXDM_GETLINEINFO 5 +#define MXDM_GETLINECONTROLS 6 +#define MXDM_GETCONTROLDETAILS 7 +#define MXDM_SETCONTROLDETAILS 8 + +/* pre-defined joystick types */ +#define JOY_HW_NONE 0 +#define JOY_HW_CUSTOM 1 +#define JOY_HW_2A_2B_GENERIC 2 +#define JOY_HW_2A_4B_GENERIC 3 +#define JOY_HW_2B_GAMEPAD 4 +#define JOY_HW_2B_FLIGHTYOKE 5 +#define JOY_HW_2B_FLIGHTYOKETHROTTLE 6 +#define JOY_HW_3A_2B_GENERIC 7 +#define JOY_HW_3A_4B_GENERIC 8 +#define JOY_HW_4B_GAMEPAD 9 +#define JOY_HW_4B_FLIGHTYOKE 10 +#define JOY_HW_4B_FLIGHTYOKETHROTTLE 11 +#define JOY_HW_LASTENTRY 12 + +/* calibration flags */ +#define JOY_ISCAL_XY 0x00000001l /* XY are calibrated */ +#define JOY_ISCAL_Z 0x00000002l /* Z is calibrated */ +#define JOY_ISCAL_R 0x00000004l /* R is calibrated */ +#define JOY_ISCAL_U 0x00000008l /* U is calibrated */ +#define JOY_ISCAL_V 0x00000010l /* V is calibrated */ +#define JOY_ISCAL_POV 0x00000020l /* POV is calibrated */ + +/* point of view constants */ +#define JOY_POV_NUMDIRS 4 +#define JOY_POVVAL_FORWARD 0 +#define JOY_POVVAL_BACKWARD 1 +#define JOY_POVVAL_LEFT 2 +#define JOY_POVVAL_RIGHT 3 + +/* Specific settings for joystick hardware */ +#define JOY_HWS_HASZ 0x00000001l /* has Z info? */ +#define JOY_HWS_HASPOV 0x00000002l /* point of view hat present */ +#define JOY_HWS_POVISBUTTONCOMBOS 0x00000004l /* pov done through combo of buttons */ +#define JOY_HWS_POVISPOLL 0x00000008l /* pov done through polling */ +#define JOY_HWS_ISYOKE 0x00000010l /* joystick is a flight yoke */ +#define JOY_HWS_ISGAMEPAD 0x00000020l /* joystick is a game pad */ +#define JOY_HWS_ISCARCTRL 0x00000040l /* joystick is a car controller */ +/* X defaults to J1 X axis */ +#define JOY_HWS_XISJ1Y 0x00000080l /* X is on J1 Y axis */ +#define JOY_HWS_XISJ2X 0x00000100l /* X is on J2 X axis */ +#define JOY_HWS_XISJ2Y 0x00000200l /* X is on J2 Y axis */ +/* Y defaults to J1 Y axis */ +#define JOY_HWS_YISJ1X 0x00000400l /* Y is on J1 X axis */ +#define JOY_HWS_YISJ2X 0x00000800l /* Y is on J2 X axis */ +#define JOY_HWS_YISJ2Y 0x00001000l /* Y is on J2 Y axis */ +/* Z defaults to J2 Y axis */ +#define JOY_HWS_ZISJ1X 0x00002000l /* Z is on J1 X axis */ +#define JOY_HWS_ZISJ1Y 0x00004000l /* Z is on J1 Y axis */ +#define JOY_HWS_ZISJ2X 0x00008000l /* Z is on J2 X axis */ +/* POV defaults to J2 Y axis, if it is not button based */ +#define JOY_HWS_POVISJ1X 0x00010000l /* pov done through J1 X axis */ +#define JOY_HWS_POVISJ1Y 0x00020000l /* pov done through J1 Y axis */ +#define JOY_HWS_POVISJ2X 0x00040000l /* pov done through J2 X axis */ +/* R defaults to J2 X axis */ +#define JOY_HWS_HASR 0x00080000l /* has R (4th axis) info */ +#define JOY_HWS_RISJ1X 0x00100000l /* R done through J1 X axis */ +#define JOY_HWS_RISJ1Y 0x00200000l /* R done through J1 Y axis */ +#define JOY_HWS_RISJ2Y 0x00400000l /* R done through J2 X axis */ +/* U & V for future hardware */ +#define JOY_HWS_HASU 0x00800000l /* has U (5th axis) info */ +#define JOY_HWS_HASV 0x01000000l /* has V (6th axis) info */ + +/* Usage settings */ +#define JOY_US_HASRUDDER 0x00000001l /* joystick configured with rudder */ +#define JOY_US_PRESENT 0x00000002l /* is joystick actually present? */ +#define JOY_US_ISOEM 0x00000004l /* joystick is an OEM defined type */ + + +/* struct for storing x,y, z, and rudder values */ +typedef struct joypos_tag { + DWORD dwX; + DWORD dwY; + DWORD dwZ; + DWORD dwR; + DWORD dwU; + DWORD dwV; +} JOYPOS, *LPJOYPOS; + +/* struct for storing ranges */ +typedef struct joyrange_tag { + JOYPOS jpMin; + JOYPOS jpMax; + JOYPOS jpCenter; +} JOYRANGE,*LPJOYRANGE; + +typedef struct joyreguservalues_tag { + DWORD dwTimeOut; /* value at which to timeout joystick polling */ + JOYRANGE jrvRanges; /* range of values app wants returned for axes */ + JOYPOS jpDeadZone; /* area around center to be considered + as "dead". specified as a percentage + (0-100). Only X & Y handled by system driver */ +} JOYREGUSERVALUES, *LPJOYREGUSERVALUES; + +typedef struct joyreghwsettings_tag { + DWORD dwFlags; + DWORD dwNumButtons; /* number of buttons */ +} JOYREGHWSETTINGS, *LPJOYHWSETTINGS; + +/* range of values returned by the hardware (filled in by calibration) */ +typedef struct joyreghwvalues_tag { + JOYRANGE jrvHardware; /* values returned by hardware */ + DWORD dwPOVValues[JOY_POV_NUMDIRS];/* POV values returned by hardware */ + DWORD dwCalFlags; /* what has been calibrated */ +} JOYREGHWVALUES, *LPJOYREGHWVALUES; + +/* hardware configuration */ +typedef struct joyreghwconfig_tag { + JOYREGHWSETTINGS hws; /* hardware settings */ + DWORD dwUsageSettings;/* usage settings */ + JOYREGHWVALUES hwv; /* values returned by hardware */ + DWORD dwType; /* type of joystick */ + DWORD dwReserved; /* reserved for OEM drivers */ +} JOYREGHWCONFIG, *LPJOYREGHWCONFIG; + +/* joystick calibration info structure */ +typedef struct joycalibrate_tag { + UINT wXbase; + UINT wXdelta; + UINT wYbase; + UINT wYdelta; + UINT wZbase; + UINT wZdelta; +} JOYCALIBRATE; +typedef JOYCALIBRATE *LPJOYCALIBRATE; + +/* prototype for joystick message function */ +typedef UINT (CALLBACK * JOYDEVMSGPROC)(DWORD dwID, UINT uMessage, LPARAM lParam1, LPARAM lParam2); +typedef JOYDEVMSGPROC *LPJOYDEVMSGPROC; + +/* messages sent to joystick driver's DriverProc() function */ +#define JDD_GETNUMDEVS (DRV_RESERVED + 0x0001) +#define JDD_GETDEVCAPS (DRV_RESERVED + 0x0002) +#define JDD_GETPOS (DRV_RESERVED + 0x0101) +#define JDD_SETCALIBRATION (DRV_RESERVED + 0x0102) +#define JDD_CONFIGCHANGED (DRV_RESERVED + 0x0103) +#define JDD_GETPOSEX (DRV_RESERVED + 0x0104) + +#define MCI_MAX_DEVICE_TYPE_LENGTH 80 + +#define MCI_FALSE (MCI_STRING_OFFSET + 19) +#define MCI_TRUE (MCI_STRING_OFFSET + 20) + +#define MCI_FORMAT_RETURN_BASE MCI_FORMAT_MILLISECONDS_S +#define MCI_FORMAT_MILLISECONDS_S (MCI_STRING_OFFSET + 21) +#define MCI_FORMAT_HMS_S (MCI_STRING_OFFSET + 22) +#define MCI_FORMAT_MSF_S (MCI_STRING_OFFSET + 23) +#define MCI_FORMAT_FRAMES_S (MCI_STRING_OFFSET + 24) +#define MCI_FORMAT_SMPTE_24_S (MCI_STRING_OFFSET + 25) +#define MCI_FORMAT_SMPTE_25_S (MCI_STRING_OFFSET + 26) +#define MCI_FORMAT_SMPTE_30_S (MCI_STRING_OFFSET + 27) +#define MCI_FORMAT_SMPTE_30DROP_S (MCI_STRING_OFFSET + 28) +#define MCI_FORMAT_BYTES_S (MCI_STRING_OFFSET + 29) +#define MCI_FORMAT_SAMPLES_S (MCI_STRING_OFFSET + 30) +#define MCI_FORMAT_TMSF_S (MCI_STRING_OFFSET + 31) + +#define MCI_VD_FORMAT_TRACK_S (MCI_VD_OFFSET + 5) + +#define WAVE_FORMAT_PCM_S (MCI_WAVE_OFFSET + 0) +#define WAVE_MAPPER_S (MCI_WAVE_OFFSET + 1) + +#define MCI_SEQ_MAPPER_S (MCI_SEQ_OFFSET + 5) +#define MCI_SEQ_FILE_S (MCI_SEQ_OFFSET + 6) +#define MCI_SEQ_MIDI_S (MCI_SEQ_OFFSET + 7) +#define MCI_SEQ_SMPTE_S (MCI_SEQ_OFFSET + 8) +#define MCI_SEQ_FORMAT_SONGPTR_S (MCI_SEQ_OFFSET + 9) +#define MCI_SEQ_NONE_S (MCI_SEQ_OFFSET + 10) +#define MIDIMAPPER_S (MCI_SEQ_OFFSET + 11) + +#define MCI_RESOURCE_RETURNED 0x00010000 /* resource ID */ +#define MCI_COLONIZED3_RETURN 0x00020000 /* colonized ID, 3 bytes data */ +#define MCI_COLONIZED4_RETURN 0x00040000 /* colonized ID, 4 bytes data */ +#define MCI_INTEGER_RETURNED 0x00080000 /* integer conversion needed */ +#define MCI_RESOURCE_DRIVER 0x00100000 /* driver owns returned resource */ + +#define MCI_NO_COMMAND_TABLE 0xFFFF + +#define MCI_COMMAND_HEAD 0 +#define MCI_STRING 1 +#define MCI_INTEGER 2 +#define MCI_END_COMMAND 3 +#define MCI_RETURN 4 +#define MCI_FLAG 5 +#define MCI_END_COMMAND_LIST 6 +#define MCI_RECT 7 +#define MCI_CONSTANT 8 +#define MCI_END_CONSTANT 9 + +#define MAKEMCIRESOURCE(wRet, wRes) MAKELRESULT((wRet), (wRes)) + +typedef struct { + DWORD dwCallback; + DWORD dwInstance; + HMIDIOUT hMidi; + DWORD dwFlags; +} PORTALLOC, *LPPORTALLOC; + +typedef struct { + HWAVE hWave; + LPWAVEFORMATEX lpFormat; + DWORD dwCallback; + DWORD dwInstance; + UINT uMappedDeviceID; + DWORD dnDevNode; +} WAVEOPENDESC, *LPWAVEOPENDESC; + +typedef struct { + DWORD dwStreamID; + WORD wDeviceID; +} MIDIOPENSTRMID; + +typedef struct { + HMIDI hMidi; + DWORD dwCallback; + DWORD dwInstance; + DWORD dnDevNode; + DWORD cIds; + MIDIOPENSTRMID rgIds; +} MIDIOPENDESC, *LPMIDIOPENDESC; + +typedef struct tMIXEROPENDESC +{ + HMIXEROBJ hmx; + LPVOID pReserved0; + DWORD dwCallback; + DWORD dwInstance; +} MIXEROPENDESC, *LPMIXEROPENDESC; + +typedef struct { + UINT wDeviceID; /* device ID */ + LPSTR lpstrParams; /* parameter string for entry in SYSTEM.INI */ + UINT wCustomCommandTable; /* custom command table (0xFFFF if none) * filled in by the driver */ + UINT wType; /* driver type (filled in by the driver) */ +} MCI_OPEN_DRIVER_PARMSA, *LPMCI_OPEN_DRIVER_PARMSA; + +typedef struct { + UINT wDeviceID; /* device ID */ + LPWSTR lpstrParams; /* parameter string for entry in SYSTEM.INI */ + UINT wCustomCommandTable; /* custom command table (0xFFFF if none) * filled in by the driver */ + UINT wType; /* driver type (filled in by the driver) */ +} MCI_OPEN_DRIVER_PARMSW, *LPMCI_OPEN_DRIVER_PARMSW; + +//DECL_WINELIB_TYPE_AW(MCI_OPEN_DRIVER_PARMS) +//DECL_WINELIB_TYPE_AW(LPMCI_OPEN_DRIVER_PARMS) + +DWORD WINAPI mciGetDriverData(UINT uDeviceID); +BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD dwData); +UINT WINAPI mciDriverYield(UINT uDeviceID); +BOOL WINAPI mciDriverNotify(HWND hwndCallback, UINT uDeviceID, + UINT uStatus); +UINT WINAPI mciLoadCommandResource(HINSTANCE hInstance, + LPCWSTR lpResName, UINT uType); +BOOL WINAPI mciFreeCommandResource(UINT uTable); + +#define DCB_NULL 0x0000 +#define DCB_WINDOW 0x0001 /* dwCallback is a HWND */ +#define DCB_TASK 0x0002 /* dwCallback is a HTASK */ +#define DCB_FUNCTION 0x0003 /* dwCallback is a FARPROC */ +#define DCB_EVENT 0x0005 /* dwCallback is an EVENT Handler */ +#define DCB_TYPEMASK 0x0007 +#define DCB_NOSWITCH 0x0008 /* don't switch stacks for callback */ + +BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev, + UINT wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2); + +#include "poppack.h" + +#endif /* __MMDDK_H */ diff --git a/reactos/include/wine/windef16.h b/reactos/include/wine/windef16.h new file mode 100644 index 00000000000..b3c1f01b9bb --- /dev/null +++ b/reactos/include/wine/windef16.h @@ -0,0 +1,146 @@ +/* + * Basic type definitions for 16 bit variations on Windows types. + * These types are provided mostly to insure compatibility with + * 16 bit windows code. + * + * Copyright (C) the Wine project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_WINDEF16_H +#define __WINE_WINDEF16_H + +// #include "windef.h" + +/* Standard data types */ + +typedef unsigned short BOOL16; +typedef DWORD SEGPTR; + +typedef UINT16 HANDLE16; +typedef HANDLE16 *LPHANDLE16; + +typedef UINT16 WPARAM16; +typedef INT16 *LPINT16; +typedef UINT16 *LPUINT16; + +#define MAKESEGPTR(seg,off) ((SEGPTR)MAKELONG(off,seg)) + +#define HFILE_ERROR16 ((HFILE16)-1) + +#define DECLARE_HANDLE16(a) \ + typedef HANDLE16 a##16; \ + typedef a##16 *P##a##16; \ + typedef a##16 *NP##a##16; \ + typedef a##16 *LP##a##16 + +DECLARE_HANDLE16(HACMDRIVERID); +DECLARE_HANDLE16(HACMDRIVER); +DECLARE_HANDLE16(HACMOBJ); +DECLARE_HANDLE16(HACMSTREAM); +DECLARE_HANDLE16(HMETAFILEPICT); + +DECLARE_HANDLE16(HACCEL); +DECLARE_HANDLE16(HBITMAP); +DECLARE_HANDLE16(HBRUSH); +DECLARE_HANDLE16(HCOLORSPACE); +DECLARE_HANDLE16(HCURSOR); +DECLARE_HANDLE16(HDC); +DECLARE_HANDLE16(HDROP); +DECLARE_HANDLE16(HDRVR); +DECLARE_HANDLE16(HDWP); +DECLARE_HANDLE16(HENHMETAFILE); +DECLARE_HANDLE16(HFILE); +DECLARE_HANDLE16(HFONT); +DECLARE_HANDLE16(HICON); +DECLARE_HANDLE16(HINSTANCE); +DECLARE_HANDLE16(HKEY); +DECLARE_HANDLE16(HMENU); +DECLARE_HANDLE16(HMETAFILE); +DECLARE_HANDLE16(HMIDI); +DECLARE_HANDLE16(HMIDIIN); +DECLARE_HANDLE16(HMIDIOUT); +DECLARE_HANDLE16(HMIDISTRM); +DECLARE_HANDLE16(HMIXER); +DECLARE_HANDLE16(HMIXEROBJ); +DECLARE_HANDLE16(HMMIO); +DECLARE_HANDLE16(HPALETTE); +DECLARE_HANDLE16(HPEN); +DECLARE_HANDLE16(HQUEUE); +DECLARE_HANDLE16(HRGN); +DECLARE_HANDLE16(HRSRC); +DECLARE_HANDLE16(HTASK); +DECLARE_HANDLE16(HWAVE); +DECLARE_HANDLE16(HWAVEIN); +DECLARE_HANDLE16(HWAVEOUT); +DECLARE_HANDLE16(HWINSTA); +DECLARE_HANDLE16(HDESK); +DECLARE_HANDLE16(HWND); +DECLARE_HANDLE16(HKL); +DECLARE_HANDLE16(HIC); +DECLARE_HANDLE16(HRASCONN); +#undef DECLARE_HANDLE16 + +typedef HINSTANCE16 HMODULE16; +typedef HANDLE16 HGDIOBJ16; +typedef HANDLE16 HGLOBAL16; +typedef HANDLE16 HLOCAL16; + +#include "pshpack1.h" + +/* The SIZE structure */ + +typedef struct +{ + INT16 cx; + INT16 cy; +} SIZE16, *PSIZE16, *LPSIZE16; + +/* The POINT structure */ + +typedef struct +{ + INT16 x; + INT16 y; +} POINT16, *PPOINT16, *LPPOINT16; + +/* The RECT structure */ + +typedef struct +{ + INT16 left; + INT16 top; + INT16 right; + INT16 bottom; +} RECT16, *LPRECT16; + +#include "poppack.h" + +/* Callback function pointers types */ + +typedef LRESULT (CALLBACK *DRIVERPROC16)(DWORD,HDRVR16,UINT16,LPARAM,LPARAM); +typedef BOOL16 (CALLBACK *DLGPROC16)(HWND16,UINT16,WPARAM16,LPARAM); +typedef INT16 (CALLBACK *EDITWORDBREAKPROC16)(LPSTR,INT16,INT16,INT16); +typedef LRESULT (CALLBACK *FARPROC16)(); +typedef INT16 (CALLBACK *PROC16)(); +typedef BOOL16 (CALLBACK *GRAYSTRINGPROC16)(HDC16,LPARAM,INT16); +typedef LRESULT (CALLBACK *HOOKPROC16)(INT16,WPARAM16,LPARAM); +typedef BOOL16 (CALLBACK *PROPENUMPROC16)(HWND16,SEGPTR,HANDLE16); +typedef VOID (CALLBACK *TIMERPROC16)(HWND16,UINT16,UINT16,DWORD); +typedef LRESULT (CALLBACK *WNDENUMPROC16)(HWND16,LPARAM); +typedef LRESULT (CALLBACK *WNDPROC16)(HWND16,UINT16,WPARAM16,LPARAM); + +#endif /* __WINE_WINDEF16_H */ diff --git a/reactos/lib/winmm/Makefile b/reactos/lib/winmm/Makefile index 01ad21b1f88..6f092c63109 100644 --- a/reactos/lib/winmm/Makefile +++ b/reactos/lib/winmm/Makefile @@ -8,7 +8,7 @@ TARGET_NAME = winmm TARGET_BASE = 0x777c0000 -TARGET_CFLAGS = +TARGET_CFLAGS = -D__WINE_FOR_REACTOS__ # require os code to explicitly request A/W version of structs/functions TARGET_CFLAGS += -D_DISABLE_TIDENTS @@ -16,11 +16,9 @@ TARGET_CFLAGS += -D_DISABLE_TIDENTS TARGET_SDKLIBS = ntdll.a kernel32.a TARGET_OBJECTS = \ - dllmain.o \ - midiin.o \ - midiout.o \ - time.o \ -# misc/stubs.o + winmm.o \ + lolvldrv.o \ + driver.o include $(PATH_TO_TOP)/rules.mak diff --git a/reactos/lib/winmm/driver.c b/reactos/lib/winmm/driver.c new file mode 100644 index 00000000000..7255c0ff3bb --- /dev/null +++ b/reactos/lib/winmm/driver.c @@ -0,0 +1,543 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/* + * WINE Drivers functions + * + * Copyright 1994 Martin Ayotte + * Copyright 1998 Marcus Meissner + * Copyright 1999 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef __WINE_FOR_REACTOS__ + +#include "internal.h" +#include +#include +typedef UINT *LPUINT; + +#else + +#include "heap.h" +#include "windef.h" +#include "wingdi.h" +#include "winuser.h" +#include "wine/debug.h" + +#endif + +#include +#include "mmddk.h" +#include "winemm.h" + +#ifndef __WINE_FOR_REACTOS__ +WINE_DEFAULT_DEBUG_CHANNEL(driver); +#endif + +static LPWINE_DRIVER lpDrvItemList /* = NULL */; + +WINE_MMTHREAD* (*pFnGetMMThread16)(HANDLE16 h) /* = NULL */; +LPWINE_DRIVER (*pFnOpenDriver16)(LPCSTR,LPCSTR,LPARAM) /* = NULL */; +LRESULT (*pFnCloseDriver16)(HDRVR16,LPARAM,LPARAM) /* = NULL */; +LRESULT (*pFnSendMessage16)(HDRVR16,UINT,LPARAM,LPARAM) /* = NULL */; + +/************************************************************************** + * DRIVER_GetNumberOfModuleRefs [internal] + * + * Returns the number of open drivers which share the same module. + */ +static unsigned DRIVER_GetNumberOfModuleRefs(HMODULE hModule, WINE_DRIVER** found) +{ + LPWINE_DRIVER lpDrv; + unsigned count = 0; + + if (found) *found = NULL; + for (lpDrv = lpDrvItemList; lpDrv; lpDrv = lpDrv->lpNextItem) + { + if (!(lpDrv->dwFlags & WINE_GDF_16BIT) && lpDrv->d.d32.hModule == hModule) + { + if (found && !*found) *found = lpDrv; + count++; + } + } + return count; +} + +/************************************************************************** + * DRIVER_FindFromHDrvr [internal] + * + * From a hDrvr being 32 bits, returns the WINE internal structure. + */ +LPWINE_DRIVER DRIVER_FindFromHDrvr(HDRVR hDrvr) +{ + LPWINE_DRIVER d = (LPWINE_DRIVER)hDrvr; + + if (hDrvr && HeapValidate(GetProcessHeap(), 0, d) && d->dwMagic == WINE_DI_MAGIC) { + return d; + } + return NULL; +} + +/************************************************************************** + * DRIVER_SendMessage [internal] + */ +static LRESULT inline DRIVER_SendMessage(LPWINE_DRIVER lpDrv, UINT msg, + LPARAM lParam1, LPARAM lParam2) +{ + LRESULT ret = 0; + + if (lpDrv->dwFlags & WINE_GDF_16BIT) { + /* no need to check mmsystem presence: the driver must have been opened as a 16 bit one, + */ + if (pFnSendMessage16) + ret = pFnSendMessage16(lpDrv->d.d16.hDriver16, msg, lParam1, lParam2); + } else { + TRACE("Before call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx\n", + lpDrv->d.d32.lpDrvProc, lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2); + ret = lpDrv->d.d32.lpDrvProc(lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2); + TRACE("After call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx => %08lx\n", + lpDrv->d.d32.lpDrvProc, lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2, ret); + } + return ret; +} + +/************************************************************************** + * SendDriverMessage [WINMM.@] + * DrvSendMessage [WINMM.@] + */ +LRESULT WINAPI SendDriverMessage(HDRVR hDriver, UINT msg, LPARAM lParam1, + LPARAM lParam2) +{ + LPWINE_DRIVER lpDrv; + LRESULT retval = 0; + + TRACE("(%p, %04X, %08lX, %08lX)\n", hDriver, msg, lParam1, lParam2); + + if ((lpDrv = DRIVER_FindFromHDrvr(hDriver)) != NULL) { + retval = DRIVER_SendMessage(lpDrv, msg, lParam1, lParam2); + } else { + WARN("Bad driver handle %p\n", hDriver); + } + TRACE("retval = %ld\n", retval); + + return retval; +} + +/************************************************************************** + * DRIVER_RemoveFromList [internal] + * + * Generates all the logic to handle driver closure / deletion + * Removes a driver struct to the list of open drivers. + */ +static BOOL DRIVER_RemoveFromList(LPWINE_DRIVER lpDrv) +{ + if (!(lpDrv->dwFlags & WINE_GDF_16BIT)) { + /* last of this driver in list ? */ + if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 1) { + DRIVER_SendMessage(lpDrv, DRV_DISABLE, 0L, 0L); + DRIVER_SendMessage(lpDrv, DRV_FREE, 0L, 0L); + } + } + + if (lpDrv->lpPrevItem) + lpDrv->lpPrevItem->lpNextItem = lpDrv->lpNextItem; + else + lpDrvItemList = lpDrv->lpNextItem; + if (lpDrv->lpNextItem) + lpDrv->lpNextItem->lpPrevItem = lpDrv->lpPrevItem; + /* trash magic number */ + lpDrv->dwMagic ^= 0xa5a5a5a5; + + return TRUE; +} + +/************************************************************************** + * DRIVER_AddToList [internal] + * + * Adds a driver struct to the list of open drivers. + * Generates all the logic to handle driver creation / open. + */ +static BOOL DRIVER_AddToList(LPWINE_DRIVER lpNewDrv, LPARAM lParam1, LPARAM lParam2) +{ + lpNewDrv->dwMagic = WINE_DI_MAGIC; + /* First driver to be loaded for this module, need to load correctly the module */ + if (!(lpNewDrv->dwFlags & WINE_GDF_16BIT)) { + /* first of this driver in list ? */ + if (DRIVER_GetNumberOfModuleRefs(lpNewDrv->d.d32.hModule, NULL) == 0) { + if (DRIVER_SendMessage(lpNewDrv, DRV_LOAD, 0L, 0L) != DRV_SUCCESS) { + TRACE("DRV_LOAD failed on driver 0x%08lx\n", (DWORD)lpNewDrv); + return FALSE; + } + /* returned value is not checked */ + DRIVER_SendMessage(lpNewDrv, DRV_ENABLE, 0L, 0L); + } + } + + lpNewDrv->lpNextItem = NULL; + if (lpDrvItemList == NULL) { + lpDrvItemList = lpNewDrv; + lpNewDrv->lpPrevItem = NULL; + } else { + LPWINE_DRIVER lpDrv = lpDrvItemList; /* find end of list */ + while (lpDrv->lpNextItem != NULL) + lpDrv = lpDrv->lpNextItem; + + lpDrv->lpNextItem = lpNewDrv; + lpNewDrv->lpPrevItem = lpDrv; + } + + if (!(lpNewDrv->dwFlags & WINE_GDF_16BIT)) { + /* Now just open a new instance of a driver on this module */ + lpNewDrv->d.d32.dwDriverID = DRIVER_SendMessage(lpNewDrv, DRV_OPEN, lParam1, lParam2); + + if (lpNewDrv->d.d32.dwDriverID == 0) { + TRACE("DRV_OPEN failed on driver 0x%08lx\n", (DWORD)lpNewDrv); + DRIVER_RemoveFromList(lpNewDrv); + return FALSE; + } + } + return TRUE; +} + +/************************************************************************** + * DRIVER_GetLibName [internal] + * + */ +BOOL DRIVER_GetLibName(LPCSTR keyName, LPCSTR sectName, LPSTR buf, int sz) +{ + /* should also do some registry diving */ + return GetPrivateProfileStringA(sectName, keyName, "", buf, sz, "SYSTEM.INI"); +} + +/************************************************************************** + * DRIVER_TryOpenDriver32 [internal] + * + * Tries to load a 32 bit driver whose DLL's (module) name is fn + */ +LPWINE_DRIVER DRIVER_TryOpenDriver32(LPCSTR fn, LPARAM lParam2) +{ + LPWINE_DRIVER lpDrv = NULL; + HMODULE hModule = 0; + LPSTR ptr; + LPCSTR cause = 0; + + TRACE("(%s, %08lX);\n", debugstr_a(fn), lParam2); + + if ((ptr = strchr(fn, ' ')) != NULL) { + *ptr++ = '\0'; + while (*ptr == ' ') ptr++; + if (*ptr == '\0') ptr = NULL; + } + + lpDrv = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_DRIVER)); + if (lpDrv == NULL) {cause = "OOM"; goto exit;} + + if ((hModule = LoadLibraryA(fn)) == 0) {cause = "Not a 32 bit lib"; goto exit;} + + lpDrv->d.d32.lpDrvProc = (DRIVERPROC)GetProcAddress(hModule, "DriverProc"); + if (lpDrv->d.d32.lpDrvProc == NULL) {cause = "no DriverProc"; goto exit;} + + lpDrv->dwFlags = 0; + lpDrv->d.d32.hModule = hModule; + lpDrv->d.d32.dwDriverID = 0; + + /* Win32 installable drivers must support a two phase opening scheme: + * + first open with NULL as lParam2 (session instance), + * + then do a second open with the real non null lParam2) + */ + if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 0 && lParam2) + { + LPWINE_DRIVER ret; + + if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, 0L)) + { + cause = "load0 failed"; + goto exit; + } + ret = DRIVER_TryOpenDriver32(fn, lParam2); + if (!ret) + { + CloseDriver((HDRVR)lpDrv, 0L, 0L); + cause = "load1 failed"; + goto exit; + } + return ret; + } + + if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, lParam2)) + {cause = "load failed"; goto exit;} + + TRACE("=> %p\n", lpDrv); + return lpDrv; + exit: + FreeLibrary(hModule); + HeapFree(GetProcessHeap(), 0, lpDrv); + TRACE("Unable to load 32 bit module %s: %s\n", debugstr_a(fn), cause); + return NULL; +} + +/************************************************************************** + * OpenDriverA [WINMM.@] + * DrvOpenA [WINMM.@] + * (0,1,DRV_LOAD ,0 ,0) + * (0,1,DRV_ENABLE,0 ,0) + * (0,1,DRV_OPEN ,buf[256],0) + */ +HDRVR WINAPI OpenDriverA(LPCSTR lpDriverName, LPCSTR lpSectionName, LPARAM lParam2) +{ + LPWINE_DRIVER lpDrv = NULL; + char libName[128]; + LPCSTR lsn = lpSectionName; + + TRACE("(%s, %s, 0x%08lx);\n", debugstr_a(lpDriverName), debugstr_a(lpSectionName), lParam2); + + if (lsn == NULL) { + lstrcpynA(libName, lpDriverName, sizeof(libName)); + + if ((lpDrv = DRIVER_TryOpenDriver32(libName, lParam2))) + goto the_end; + lsn = "Drivers32"; + } + if (DRIVER_GetLibName(lpDriverName, lsn, libName, sizeof(libName)) && + (lpDrv = DRIVER_TryOpenDriver32(libName, lParam2))) + goto the_end; + + /* now we will try a 16 bit driver (and add all the glue to make it work... which + * is located in our mmsystem implementation) + * so ensure, we can load our mmsystem, otherwise just fail + */ + WINMM_CheckForMMSystem(); + if (pFnOpenDriver16 && + (lpDrv = pFnOpenDriver16(lpDriverName, lpSectionName, lParam2))) + { + if (DRIVER_AddToList(lpDrv, 0, lParam2)) goto the_end; + HeapFree(GetProcessHeap(), 0, lpDrv); + } + TRACE("Failed to open driver %s from system.ini file, section %s\n", debugstr_a(lpDriverName), debugstr_a(lpSectionName)); + return 0; + + the_end: + if (lpDrv) TRACE("=> %08lx\n", (DWORD)lpDrv); + return (HDRVR)lpDrv; +} + +/************************************************************************** + * OpenDriver [WINMM.@] + * DrvOpen [WINMM.@] + */ +HDRVR WINAPI OpenDriverW(LPCWSTR lpDriverName, LPCWSTR lpSectionName, LPARAM lParam) +{ + LPSTR dn = HEAP_strdupWtoA(GetProcessHeap(), 0, lpDriverName); + LPSTR sn = HEAP_strdupWtoA(GetProcessHeap(), 0, lpSectionName); + HDRVR ret = OpenDriverA(dn, sn, lParam); + + if (dn) HeapFree(GetProcessHeap(), 0, dn); + if (sn) HeapFree(GetProcessHeap(), 0, sn); + return ret; +} + +/************************************************************************** + * CloseDriver [WINMM.@] + * DrvClose [WINMM.@] + */ +LRESULT WINAPI CloseDriver(HDRVR hDrvr, LPARAM lParam1, LPARAM lParam2) +{ + LPWINE_DRIVER lpDrv; + + TRACE("(%p, %08lX, %08lX);\n", hDrvr, lParam1, lParam2); + + if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) + { + if (lpDrv->dwFlags & WINE_GDF_16BIT) + { + if (pFnCloseDriver16) + pFnCloseDriver16(lpDrv->d.d16.hDriver16, lParam1, lParam2); + } + else + { + DRIVER_SendMessage(lpDrv, DRV_CLOSE, lParam1, lParam2); + lpDrv->d.d32.dwDriverID = 0; + } + if (DRIVER_RemoveFromList(lpDrv)) { + if (!(lpDrv->dwFlags & WINE_GDF_16BIT)) + { + LPWINE_DRIVER lpDrv0; + + /* if driver has an opened session instance, we have to close it too */ + if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, &lpDrv0) == 1) + { + DRIVER_SendMessage(lpDrv0, DRV_CLOSE, 0L, 0L); + lpDrv0->d.d32.dwDriverID = 0; + DRIVER_RemoveFromList(lpDrv0); + FreeLibrary(lpDrv->d.d32.hModule); + HeapFree(GetProcessHeap(), 0, lpDrv0); + } + FreeLibrary(lpDrv->d.d32.hModule); + } + HeapFree(GetProcessHeap(), 0, lpDrv); + return TRUE; + } + } + WARN("Failed to close driver\n"); + return FALSE; +} + +/************************************************************************** + * GetDriverFlags [WINMM.@] + * [in] hDrvr handle to the driver + * + * Returns: + * 0x00000000 if hDrvr is an invalid handle + * 0x80000000 if hDrvr is a valid 32 bit driver + * 0x90000000 if hDrvr is a valid 16 bit driver + * + * native WINMM doesn't return those flags + * 0x80000000 for a valid 32 bit driver and that's it + * (I may have mixed up the two flags :-( + */ +DWORD WINAPI GetDriverFlags(HDRVR hDrvr) +{ + LPWINE_DRIVER lpDrv; + DWORD ret = 0; + + TRACE("(%p)\n", hDrvr); + + if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) { + ret = WINE_GDF_EXIST | lpDrv->dwFlags; + } + return ret; +} + +/************************************************************************** + * GetDriverModuleHandle [WINMM.@] + * DrvGetModuleHandle [WINMM.@] + */ +HMODULE WINAPI GetDriverModuleHandle(HDRVR hDrvr) +{ + LPWINE_DRIVER lpDrv; + HMODULE hModule = 0; + + TRACE("(%p);\n", hDrvr); + + if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) { + if (!(lpDrv->dwFlags & WINE_GDF_16BIT)) + hModule = lpDrv->d.d32.hModule; + } + TRACE("=> %p\n", hModule); + return hModule; +} + +/************************************************************************** + * DefDriverProc [WINMM.@] + * DrvDefDriverProc [WINMM.@] + */ +LRESULT WINAPI DefDriverProc(DWORD dwDriverIdentifier, HDRVR hDrv, + UINT Msg, LPARAM lParam1, LPARAM lParam2) +{ + switch (Msg) { + case DRV_LOAD: + case DRV_FREE: + case DRV_ENABLE: + case DRV_DISABLE: + return 1; + case DRV_INSTALL: + case DRV_REMOVE: + return DRV_SUCCESS; + default: + return 0; + } +} + +/************************************************************************** + * DriverCallback [WINMM.@] + */ +BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev, + UINT wMsg, DWORD dwUser, DWORD dwParam1, + DWORD dwParam2) +{ + TRACE("(%08lX, %04X, %p, %04X, %08lX, %08lX, %08lX); !\n", + dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2); + + switch (uFlags & DCB_TYPEMASK) { + case DCB_NULL: + TRACE("Null !\n"); + if (dwCallBack) + WARN("uFlags=%04X has null DCB value, but dwCallBack=%08lX is not null !\n", uFlags, dwCallBack); + break; + case DCB_WINDOW: + TRACE("Window(%04lX) handle=%p!\n", dwCallBack, hDev); + PostMessageA((HWND)dwCallBack, wMsg, (WPARAM)hDev, dwParam1); + break; + case DCB_TASK: /* aka DCB_THREAD */ + TRACE("Task(%04lx) !\n", dwCallBack); + PostThreadMessageA(dwCallBack, wMsg, (WPARAM)hDev, dwParam1); + break; + case DCB_FUNCTION: + TRACE("Function (32 bit) !\n"); + ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2); + break; + case DCB_EVENT: + TRACE("Event(%08lx) !\n", dwCallBack); + SetEvent((HANDLE)dwCallBack); + break; + case 6: /* I would dub it DCB_MMTHREADSIGNAL */ + /* this is an undocumented DCB_ value used for mmThreads + * loword of dwCallBack contains the handle of the lpMMThd block + * which dwSignalCount has to be incremented + */ + if (pFnGetMMThread16) + { + WINE_MMTHREAD* lpMMThd = pFnGetMMThread16(LOWORD(dwCallBack)); + + TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd); + /* same as mmThreadSignal16 */ + InterlockedIncrement(&lpMMThd->dwSignalCount); + SetEvent(lpMMThd->hEvent); + /* some other stuff on lpMMThd->hVxD */ + } + break; +#if 0 + case 4: + /* this is an undocumented DCB_ value for... I don't know */ + break; +#endif + default: + WARN("Unknown callback type %d\n", uFlags & DCB_TYPEMASK); + return FALSE; + } + TRACE("Done\n"); + return TRUE; +} + +/****************************************************************** + * DRIVER_UnloadAll + * + * + */ +void DRIVER_UnloadAll(void) +{ + LPWINE_DRIVER lpDrv; + LPWINE_DRIVER lpNextDrv = NULL; + unsigned count = 0; + + for (lpDrv = lpDrvItemList; lpDrv != NULL; lpDrv = lpNextDrv) + { + lpNextDrv = lpDrv->lpNextItem; + CloseDriver((HDRVR)lpDrv, 0, 0); + count++; + } + TRACE("Unloaded %u drivers\n", count); +} diff --git a/reactos/lib/winmm/internal.h b/reactos/lib/winmm/internal.h new file mode 100644 index 00000000000..235defc6cad --- /dev/null +++ b/reactos/lib/winmm/internal.h @@ -0,0 +1,26 @@ +/* this call (GetDriverFlags) is not documented, nor the flags returned. + * here are Wine only definitions +*/ + +#ifndef __INCLUDES_ROS_WINMM_INTERNAL__ +#define __INCLUDES_ROS_WINMM_INTERNAL__ + +#ifdef __WINE_FOR_REACTOS__ + +#define WINE_GDF_EXIST 0x80000000 +#define WINE_GDF_16BIT 0x1000000 + +#define DRV_SUCCESS 0x0001 +#define DRV_FAILURE 0x0000 + +#define WARN printf +#define FIXME printf +#define TRACE printf +#define ERR printf +#define debugstr_a printf + +#define HEAP_strdupWtoA strdupWtoA + +#endif /* __WINE_FOR_REACTOS__ */ + +#endif /* __INCLUDES_ROS_WINMM_INTERNAL__ */ diff --git a/reactos/lib/winmm/lolvldrv.c b/reactos/lib/winmm/lolvldrv.c new file mode 100644 index 00000000000..0e5251dbfaf --- /dev/null +++ b/reactos/lib/winmm/lolvldrv.c @@ -0,0 +1,837 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/* + * MMSYTEM low level drivers handling functions + * + * Copyright 1999 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifdef __WINE_FOR_REACTOS__ + +#define __WINESRC__ +#include +typedef UINT *LPUINT; +#include "internal.h" + +#else + +#include "winreg.h" +#include "winver.h" +#include "wine/debug.h" +WINE_DEFAULT_DEBUG_CHANNEL(winmm); + +#endif + +#include +#include +#include +#include "winemm.h" +#include + + +#ifdef __WINE_FOR_REACTOS__ +#define HFILE_ERROR ((HFILE)-1) +typedef DWORD (*LPGetFileVersionInfoSizeA)(LPSTR lptstrFilename, LPDWORD lpdwHandle); +typedef BOOL (*LPGetFileVersionInfoA)(LPSTR lptstrFilename, DWORD dwHandle, + DWORD dwLen, LPVOID lpData); +typedef BOOL (*LPVerQueryValueA)(const LPVOID pBlock, LPSTR lpSubBlock, + LPVOID *lplpBuffer, PUINT puLen); +#else +typedef FARPROC LPGetFileVersionInfoSizeA; +typedef FARPROC LPGetFileVersionInfoA; +typedef FARPROC LPVerQueryValueA; +#endif + + +LRESULT (*pFnCallMMDrvFunc16)(FARPROC16,WORD,WORD,LONG,LONG,LONG) /* = NULL */; +unsigned (*pFnLoadMMDrvFunc16)(LPCSTR,LPWINE_DRIVER, LPWINE_MM_DRIVER) /* = NULL */; + +/* each known type of driver has an instance of this structure */ +typedef struct tagWINE_LLTYPE { + /* those attributes depend on the specification of the type */ + LPSTR typestr; /* name (for debugging) */ + BOOL bSupportMapper; /* if type is allowed to support mapper */ + MMDRV_MAPFUNC Map16To32A; /* those are function pointers to handle */ + MMDRV_UNMAPFUNC UnMap16To32A; /* the parameter conversion (16 vs 32 bit) */ + MMDRV_MAPFUNC Map32ATo16; /* when hi-func (in mmsystem or winmm) and */ + MMDRV_UNMAPFUNC UnMap32ATo16; /* low-func (in .drv) do not match */ + LPDRVCALLBACK Callback; /* handles callback for a specified type */ + /* those attributes reflect the loaded/current situation for the type */ + UINT wMaxId; /* number of loaded devices (sum across all loaded drivers */ + LPWINE_MLD lpMlds; /* "static" mlds to access the part though device IDs */ + int nMapper; /* index to mapper */ +} WINE_LLTYPE; + +static int MMDrvsHi /* = 0 */; +static WINE_MM_DRIVER MMDrvs[3]; +static LPWINE_MLD MM_MLDrvs[40]; +#define MAX_MM_MLDRVS (sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0])) + +#define A(_x,_y) {#_y, _x, NULL, NULL, NULL, NULL, NULL, 0, NULL, -1} +/* Note: the indices of this array must match the definitions + * of the MMDRV_???? manifest constants + */ +static WINE_LLTYPE llTypes[MMDRV_MAX] = { + A(TRUE, Aux), + A(FALSE, Mixer), + A(TRUE, MidiIn), + A(TRUE, MidiOut), + A(TRUE, WaveIn), + A(TRUE, WaveOut), +}; +#undef A + +/****************************************************************** + * MMDRV_InstallMap + * + * + */ +void MMDRV_InstallMap(unsigned int drv, + MMDRV_MAPFUNC mp1632, MMDRV_UNMAPFUNC um1632, + MMDRV_MAPFUNC mp3216, MMDRV_UNMAPFUNC um3216, + LPDRVCALLBACK cb) +{ + assert(drv < MMDRV_MAX); + llTypes[drv].Map16To32A = mp1632; + llTypes[drv].UnMap16To32A = um1632; + llTypes[drv].Map32ATo16 = mp3216; + llTypes[drv].UnMap32ATo16 = um1632; + llTypes[drv].Callback = cb; +} + +/****************************************************************** + * MMDRV_Is32 + * + */ +BOOL MMDRV_Is32(unsigned int idx) +{ + return MMDrvs[idx].bIs32; +} + +/************************************************************************** + * MMDRV_GetDescription32 [internal] + */ +static BOOL MMDRV_GetDescription32(const char* fname, char* buf, int buflen) +{ + OFSTRUCT ofs; + DWORD h; + LPVOID ptr = 0; + LPVOID val; + DWORD dw; + BOOL ret = FALSE; + UINT u; + LPGetFileVersionInfoSizeA pGetFileVersionInfoSizeA; + LPGetFileVersionInfoA pGetFileVersionInfoA; + LPVerQueryValueA pVerQueryValueA; + HMODULE hmodule = 0; + +#define E(_x) do {TRACE _x;goto theEnd;} while(0) + + if (OpenFile(fname, &ofs, OF_EXIST)==HFILE_ERROR) E(("Can't find file %s\n", fname)); + + if (!(hmodule = LoadLibraryA( "version.dll" ))) goto theEnd; + if (!(pGetFileVersionInfoSizeA = GetProcAddress( hmodule, "GetFileVersionInfoSizeA" ))) + goto theEnd; + if (!(pGetFileVersionInfoA = GetProcAddress( hmodule, "GetFileVersionInfoA" ))) + goto theEnd; + if (!(pVerQueryValueA = GetProcAddress( hmodule, "VerQueryValueA" ))) + goto theEnd; + + if (!(dw = pGetFileVersionInfoSizeA(ofs.szPathName, &h))) E(("Can't get FVIS\n")); + if (!(ptr = HeapAlloc(GetProcessHeap(), 0, dw))) E(("OOM\n")); + if (!pGetFileVersionInfoA(ofs.szPathName, h, dw, ptr)) E(("Can't get FVI\n")); + +#define A(_x) if (pVerQueryValueA(ptr, "\\StringFileInfo\\040904B0\\" #_x, &val, &u)) \ + TRACE(#_x " => %s\n", (LPSTR)val); else TRACE(#_x " @\n") + + A(CompanyName); + A(FileDescription); + A(FileVersion); + A(InternalName); + A(LegalCopyright); + A(OriginalFilename); + A(ProductName); + A(ProductVersion); + A(Comments); + A(LegalTrademarks); + A(PrivateBuild); + A(SpecialBuild); +#undef A + + if (!pVerQueryValueA(ptr, "\\StringFileInfo\\040904B0\\ProductName", &val, &u)) E(("Can't get product name\n")); + lstrcpynA(buf, val, buflen); + +#undef E + ret = TRUE; +theEnd: + HeapFree(GetProcessHeap(), 0, ptr); + if (hmodule) FreeLibrary( hmodule ); + return ret; +} + +/************************************************************************** + * MMDRV_GetNum [internal] + */ +UINT MMDRV_GetNum(UINT type) +{ + assert(type < MMDRV_MAX); + return llTypes[type].wMaxId; +} + +/************************************************************************** + * MMDRV_Message [internal] + */ +DWORD MMDRV_Message(LPWINE_MLD mld, WORD wMsg, DWORD dwParam1, + DWORD dwParam2, BOOL bFrom32) +{ + LPWINE_MM_DRIVER lpDrv; + DWORD ret; + WINE_MM_DRIVER_PART* part; + WINE_LLTYPE* llType = &llTypes[mld->type]; + WINMM_MapType map; + int devID; + + TRACE("(%s %u %u 0x%08lx 0x%08lx 0x%08lx %c)\n", + llTypes[mld->type].typestr, mld->uDeviceID, wMsg, + mld->dwDriverInstance, dwParam1, dwParam2, bFrom32?'Y':'N'); + + if (mld->uDeviceID == (UINT16)-1) { + if (!llType->bSupportMapper) { + WARN("uDev=-1 requested on non-mappable ll type %s\n", + llTypes[mld->type].typestr); + return MMSYSERR_BADDEVICEID; + } + devID = -1; + } else { + if (mld->uDeviceID >= llType->wMaxId) { + WARN("uDev(%u) requested >= max (%d)\n", mld->uDeviceID, llType->wMaxId); + return MMSYSERR_BADDEVICEID; + } + devID = mld->uDeviceID; + } + + lpDrv = &MMDrvs[mld->mmdIndex]; + part = &lpDrv->parts[mld->type]; + +#if 0 + /* some sanity checks */ + if (!(part->nIDMin <= devID)) + ERR("!(part->nIDMin(%d) <= devID(%d))\n", part->nIDMin, devID); + if (!(devID < part->nIDMax)) + ERR("!(devID(%d) < part->nIDMax(%d))\n", devID, part->nIDMax); +#endif + + if (lpDrv->bIs32) { + assert(part->u.fnMessage32); + + if (bFrom32) { + TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n", + mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); + ret = part->u.fnMessage32(mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); + TRACE("=> %lu\n", ret); + } else { + map = llType->Map16To32A(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2); + switch (map) { + case WINMM_MAP_NOMEM: + ret = MMSYSERR_NOMEM; + break; + case WINMM_MAP_MSGERROR: + FIXME("NIY: no conversion yet 16->32 (%u)\n", wMsg); + ret = MMSYSERR_ERROR; + break; + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n", + mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); + ret = part->u.fnMessage32(mld->uDeviceID, wMsg, mld->dwDriverInstance, + dwParam1, dwParam2); + TRACE("=> %lu\n", ret); + if (map == WINMM_MAP_OKMEM) + llType->UnMap16To32A(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2, ret); + break; + default: + FIXME("NIY\n"); + ret = MMSYSERR_NOTSUPPORTED; + break; + } + } + } else { + assert(part->u.fnMessage16 && pFnCallMMDrvFunc16); + + if (bFrom32) { + map = llType->Map32ATo16(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2); + switch (map) { + case WINMM_MAP_NOMEM: + ret = MMSYSERR_NOMEM; + break; + case WINMM_MAP_MSGERROR: + FIXME("NIY: no conversion yet 32->16 (%u)\n", wMsg); + ret = MMSYSERR_ERROR; + break; + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n", + mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); + ret = pFnCallMMDrvFunc16((FARPROC16)part->u.fnMessage16, + mld->uDeviceID, wMsg, mld->dwDriverInstance, + dwParam1, dwParam2); + TRACE("=> %lu\n", ret); + if (map == WINMM_MAP_OKMEM) + llType->UnMap32ATo16(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2, ret); + break; + default: + FIXME("NIY\n"); + ret = MMSYSERR_NOTSUPPORTED; + break; + } + } else { + TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n", + mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); + ret = pFnCallMMDrvFunc16((FARPROC16)part->u.fnMessage16, + mld->uDeviceID, wMsg, mld->dwDriverInstance, + dwParam1, dwParam2); + TRACE("=> %lu\n", ret); + } + } + return ret; +} + +/************************************************************************** + * MMDRV_Alloc [internal] + */ +LPWINE_MLD MMDRV_Alloc(UINT size, UINT type, LPHANDLE hndl, DWORD* dwFlags, + DWORD* dwCallback, DWORD* dwInstance, BOOL bFrom32) +{ + LPWINE_MLD mld; + UINT i; + + mld = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); + if (!mld) return NULL; + + /* find an empty slot in MM_MLDrvs table */ + for (i = 0; i < MAX_MM_MLDRVS; i++) if (!MM_MLDrvs[i]) break; + + if (i == MAX_MM_MLDRVS) { + /* the MM_MLDrvs table could be made growable in the future if needed */ + ERR("Too many open drivers\n"); + return NULL; + } + MM_MLDrvs[i] = mld; + *hndl = (HANDLE)(i | 0x8000); + + mld->type = type; + if ((UINT)*hndl < MMDRV_GetNum(type) || HIWORD(*hndl) != 0) { + /* FIXME: those conditions must be fulfilled so that: + * - we can distinguish between device IDs and handles + * - we can use handles as 16 or 32 bit entities + */ + ERR("Shouldn't happen. Bad allocation scheme\n"); + } + + mld->bFrom32 = bFrom32; + mld->dwFlags = HIWORD(*dwFlags); + mld->dwCallback = *dwCallback; + mld->dwClientInstance = *dwInstance; + + if (llTypes[type].Callback) + { + *dwFlags = LOWORD(*dwFlags) | CALLBACK_FUNCTION; + *dwCallback = (DWORD)llTypes[type].Callback; + *dwInstance = (DWORD)mld; /* FIXME: wouldn't some 16 bit drivers only use the loword ? */ + } + + return mld; +} + +/************************************************************************** + * MMDRV_Free [internal] + */ +void MMDRV_Free(HANDLE hndl, LPWINE_MLD mld) +{ + if ((UINT)hndl & 0x8000) { + unsigned idx = (UINT)hndl & ~0x8000; + if (idx < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0])) { + MM_MLDrvs[idx] = NULL; + HeapFree(GetProcessHeap(), 0, mld); + return; + } + } + ERR("Bad Handle %p at %p (not freed)\n", hndl, mld); +} + +/************************************************************************** + * MMDRV_Open [internal] + */ +DWORD MMDRV_Open(LPWINE_MLD mld, UINT wMsg, DWORD dwParam1, DWORD dwFlags) +{ + DWORD dwRet = MMSYSERR_BADDEVICEID; + DWORD dwInstance; + WINE_LLTYPE* llType = &llTypes[mld->type]; + + mld->dwDriverInstance = (DWORD)&dwInstance; + + if (mld->uDeviceID == (UINT)-1 || mld->uDeviceID == (UINT16)-1) { + TRACE("MAPPER mode requested !\n"); + /* check if mapper is supported by type */ + if (llType->bSupportMapper) { + if (llType->nMapper == -1) { + /* no driver for mapper has been loaded, try a dumb implementation */ + TRACE("No mapper loaded, doing it by hand\n"); + for (mld->uDeviceID = 0; mld->uDeviceID < llType->wMaxId; mld->uDeviceID++) { + if ((dwRet = MMDRV_Open(mld, wMsg, dwParam1, dwFlags)) == MMSYSERR_NOERROR) { + /* to share this function epilog */ + dwInstance = mld->dwDriverInstance; + break; + } + } + } else { + mld->uDeviceID = (UINT16)-1; + mld->mmdIndex = llType->lpMlds[-1].mmdIndex; + TRACE("Setting mmdIndex to %u\n", mld->mmdIndex); + dwRet = MMDRV_Message(mld, wMsg, dwParam1, dwFlags, TRUE); + } + } + } else { + if (mld->uDeviceID < llType->wMaxId) { + mld->mmdIndex = llType->lpMlds[mld->uDeviceID].mmdIndex; + TRACE("Setting mmdIndex to %u\n", mld->mmdIndex); + dwRet = MMDRV_Message(mld, wMsg, dwParam1, dwFlags, TRUE); + } + } + if (dwRet == MMSYSERR_NOERROR) + mld->dwDriverInstance = dwInstance; + return dwRet; +} + +/************************************************************************** + * MMDRV_Close [internal] + */ +DWORD MMDRV_Close(LPWINE_MLD mld, UINT wMsg) +{ + return MMDRV_Message(mld, wMsg, 0L, 0L, TRUE); +} + +/************************************************************************** + * MMDRV_GetByID [internal] + */ +LPWINE_MLD MMDRV_GetByID(UINT uDevID, UINT type) +{ + if (uDevID < llTypes[type].wMaxId) + return &llTypes[type].lpMlds[uDevID]; + if ((uDevID == (UINT16)-1 || uDevID == (UINT)-1) && llTypes[type].nMapper != -1) + return &llTypes[type].lpMlds[-1]; + return NULL; +} + +/************************************************************************** + * MMDRV_Get [internal] + */ +LPWINE_MLD MMDRV_Get(HANDLE _hndl, UINT type, BOOL bCanBeID) +{ + LPWINE_MLD mld = NULL; + UINT hndl = (UINT)_hndl; + + assert(type < MMDRV_MAX); + + if (hndl >= llTypes[type].wMaxId && + hndl != (UINT16)-1 && hndl != (UINT)-1) { + if (hndl & 0x8000) { + hndl = hndl & ~0x8000; + if (hndl < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0])) { + mld = MM_MLDrvs[hndl]; + if (!mld || !HeapValidate(GetProcessHeap(), 0, mld) || mld->type != type) + mld = NULL; + } + hndl = hndl | 0x8000; + } + } + if (mld == NULL && bCanBeID) { + mld = MMDRV_GetByID(hndl, type); + } + return mld; +} + +/************************************************************************** + * MMDRV_GetRelated [internal] + */ +LPWINE_MLD MMDRV_GetRelated(HANDLE hndl, UINT srcType, + BOOL bSrcCanBeID, UINT dstType) +{ + LPWINE_MLD mld; + + if ((mld = MMDRV_Get(hndl, srcType, bSrcCanBeID)) != NULL) { + WINE_MM_DRIVER_PART* part = &MMDrvs[mld->mmdIndex].parts[dstType]; + if (part->nIDMin < part->nIDMax) + return MMDRV_GetByID(part->nIDMin, dstType); + } + return NULL; +} + +/************************************************************************** + * MMDRV_PhysicalFeatures [internal] + */ +UINT MMDRV_PhysicalFeatures(LPWINE_MLD mld, UINT uMsg, DWORD dwParam1, + DWORD dwParam2) +{ + WINE_MM_DRIVER* lpDrv = &MMDrvs[mld->mmdIndex]; + + TRACE("(%p, %04x, %08lx, %08lx)\n", mld, uMsg, dwParam1, dwParam2); + + /* all those function calls are undocumented */ + switch (uMsg) { + case DRV_QUERYDRVENTRY: + lstrcpynA((LPSTR)dwParam1, lpDrv->drvname, LOWORD(dwParam2)); + break; + case DRV_QUERYDEVNODE: + *(LPDWORD)dwParam1 = 0L; /* should be DevNode */ + break; + case DRV_QUERYNAME: + WARN("NIY QueryName\n"); + break; + case DRV_QUERYDRIVERIDS: + WARN("NIY call VxD\n"); + /* should call VxD MMDEVLDR with (DevNode, dwParam1 and dwParam2) as pmts + * dwParam1 is buffer and dwParam2 is sizeof(buffer) + * I don't know where the result is stored though + */ + break; + case DRV_QUERYMAPPABLE: + return (lpDrv->bIsMapper) ? 2 : 0; + + case DRV_QUERYDSOUNDIFACE: /* Wine-specific: Retrieve DirectSound interface */ + return MMDRV_Message(mld, uMsg, dwParam1, dwParam2, TRUE); + + case DRV_QUERYDSOUNDDESC: /* Wine-specific: Retrieve DirectSound driver description*/ + return MMDRV_Message(mld, uMsg, dwParam1, dwParam2, TRUE); + + case DRV_QUERYDSOUNDGUID: /* Wine-specific: Retrieve DirectSound driver GUID */ + return MMDRV_Message(mld, uMsg, dwParam1, dwParam2, TRUE); + + default: + WARN("Unknown call %04x\n", uMsg); + return MMSYSERR_INVALPARAM; + } + return 0L; +} + +/************************************************************************** + * MMDRV_InitPerType [internal] + */ +static BOOL MMDRV_InitPerType(LPWINE_MM_DRIVER lpDrv, UINT type, UINT wMsg) +{ + WINE_MM_DRIVER_PART* part = &lpDrv->parts[type]; + DWORD ret; + UINT count = 0; + int i, k; + + part->nIDMin = part->nIDMax = 0; + + /* for DRVM_INIT and DRVM_ENABLE, dwParam2 should be PnP node */ + /* the DRVM_ENABLE is only required when the PnP node is non zero */ + + if (lpDrv->bIs32 && part->u.fnMessage32) { + ret = part->u.fnMessage32(0, DRVM_INIT, 0L, 0L, 0L); + TRACE("DRVM_INIT => %08lx\n", ret); +#if 0 + ret = part->u.fnMessage32(0, DRVM_ENABLE, 0L, 0L, 0L); + TRACE("DRVM_ENABLE => %08lx\n", ret); +#endif + count = part->u.fnMessage32(0, wMsg, 0L, 0L, 0L); + } else if (!lpDrv->bIs32 && part->u.fnMessage16 && pFnCallMMDrvFunc16) { + ret = pFnCallMMDrvFunc16((FARPROC16)part->u.fnMessage16, + 0, DRVM_INIT, 0L, 0L, 0L); + TRACE("DRVM_INIT => %08lx\n", ret); +#if 0 + ret = pFnCallMMDrvFunc16((FARPROC16)part->u.fnMessage16, + 0, DRVM_ENABLE, 0L, 0L, 0L); + TRACE("DRVM_ENABLE => %08lx\n", ret); +#endif + count = pFnCallMMDrvFunc16((FARPROC16)part->u.fnMessage16, + 0, wMsg, 0L, 0L, 0L); + } else { + return FALSE; + } + + TRACE("Got %u dev for (%s:%s)\n", count, lpDrv->drvname, llTypes[type].typestr); + + /* got some drivers */ + if (lpDrv->bIsMapper) { + /* it seems native mappers return 0 devices :-( */ + if (llTypes[type].nMapper != -1) + ERR("Two mappers for type %s (%d, %s)\n", + llTypes[type].typestr, llTypes[type].nMapper, lpDrv->drvname); + if (count > 1) + ERR("Strange: mapper with %d > 1 devices\n", count); + llTypes[type].nMapper = MMDrvsHi; + } else { + if (count == 0) + return FALSE; + part->nIDMin = llTypes[type].wMaxId; + llTypes[type].wMaxId += count; + part->nIDMax = llTypes[type].wMaxId; + } + TRACE("Setting min=%d max=%d (ttop=%d) for (%s:%s)\n", + part->nIDMin, part->nIDMax, llTypes[type].wMaxId, + lpDrv->drvname, llTypes[type].typestr); + /* realloc translation table */ + llTypes[type].lpMlds = (LPWINE_MLD) + HeapReAlloc(GetProcessHeap(), 0, (llTypes[type].lpMlds) ? llTypes[type].lpMlds - 1 : NULL, + sizeof(WINE_MLD) * (llTypes[type].wMaxId + 1)) + 1; + /* re-build the translation table */ + if (llTypes[type].nMapper != -1) { + TRACE("%s:Trans[%d] -> %s\n", llTypes[type].typestr, -1, MMDrvs[llTypes[type].nMapper].drvname); + llTypes[type].lpMlds[-1].uDeviceID = (UINT16)-1; + llTypes[type].lpMlds[-1].type = type; + llTypes[type].lpMlds[-1].mmdIndex = llTypes[type].nMapper; + llTypes[type].lpMlds[-1].dwDriverInstance = 0; + } + for (i = k = 0; i <= MMDrvsHi; i++) { + while (MMDrvs[i].parts[type].nIDMin <= k && k < MMDrvs[i].parts[type].nIDMax) { + TRACE("%s:Trans[%d] -> %s\n", llTypes[type].typestr, k, MMDrvs[i].drvname); + llTypes[type].lpMlds[k].uDeviceID = k; + llTypes[type].lpMlds[k].type = type; + llTypes[type].lpMlds[k].mmdIndex = i; + llTypes[type].lpMlds[k].dwDriverInstance = 0; + k++; + } + } + return TRUE; +} + +/************************************************************************** + * MMDRV_Install [internal] + */ +static BOOL MMDRV_Install(LPCSTR drvRegName, LPCSTR drvFileName, BOOL bIsMapper) +{ + int i, count = 0; + LPWINE_MM_DRIVER lpDrv = &MMDrvs[MMDrvsHi]; + LPWINE_DRIVER d; + + TRACE("('%s', '%s', mapper=%c);\n", drvRegName, drvFileName, bIsMapper ? 'Y' : 'N'); + + /* be sure that size of MMDrvs matches the max number of loadable drivers !! + * if not just increase size of MMDrvs */ + assert(MMDrvsHi <= sizeof(MMDrvs)/sizeof(MMDrvs[0])); + + for (i = 0; i < MMDrvsHi; i++) { + if (!strcmp(drvRegName, MMDrvs[i].drvname)) return FALSE; + } + + memset(lpDrv, 0, sizeof(*lpDrv)); + + if (!(lpDrv->hDriver = OpenDriverA(drvFileName, 0, 0))) { + WARN("Couldn't open driver '%s'\n", drvFileName); + return FALSE; + } + + d = DRIVER_FindFromHDrvr(lpDrv->hDriver); + lpDrv->bIs32 = (d->dwFlags & WINE_GDF_16BIT) ? FALSE : TRUE; + + /* Then look for xxxMessage functions */ +#define AA(_h,_w,_x,_y,_z) \ + func = (WINEMM_msgFunc##_y) _z ((_h), #_x); \ + if (func != NULL) \ + { lpDrv->parts[_w].u.fnMessage##_y = func; count++; \ + TRACE("Got %d bit func '%s'\n", _y, #_x); } + + if (lpDrv->bIs32) { + WINEMM_msgFunc32 func; + char buffer[128]; + + if (d->d.d32.hModule) { +#define A(_x,_y) AA(d->d.d32.hModule,_x,_y,32,GetProcAddress) + A(MMDRV_AUX, auxMessage); + A(MMDRV_MIXER, mxdMessage); + A(MMDRV_MIDIIN, midMessage); + A(MMDRV_MIDIOUT, modMessage); + A(MMDRV_WAVEIN, widMessage); + A(MMDRV_WAVEOUT, wodMessage); +#undef A + } +// if (TRACE_ON(winmm)) { +// if (MMDRV_GetDescription32(drvFileName, buffer, sizeof(buffer))) +// TRACE("%s => %s\n", drvFileName, buffer); +// else +// TRACE("%s => No description\n", drvFileName); +// } +// } else if (WINMM_CheckForMMSystem() && pFnLoadMMDrvFunc16) { + } if (WINMM_CheckForMMSystem() && pFnLoadMMDrvFunc16) { + count += pFnLoadMMDrvFunc16(drvFileName, d, lpDrv); + } +#undef AA + + if (!count) { + CloseDriver(lpDrv->hDriver, 0, 0); + WARN("No message functions found\n"); + return FALSE; + } + + /* FIXME: being a mapper or not should be known by another way */ + /* it's known for NE drvs (the description is of the form '*mapper: *' + * I don't have any clue for PE drvs + */ + lpDrv->bIsMapper = bIsMapper; + lpDrv->drvname = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(drvRegName) + 1), drvRegName); + + /* Finish init and get the count of the devices */ + MMDRV_InitPerType(lpDrv, MMDRV_AUX, AUXDM_GETNUMDEVS); + MMDRV_InitPerType(lpDrv, MMDRV_MIXER, MXDM_GETNUMDEVS); + MMDRV_InitPerType(lpDrv, MMDRV_MIDIIN, MIDM_GETNUMDEVS); + MMDRV_InitPerType(lpDrv, MMDRV_MIDIOUT, MODM_GETNUMDEVS); + MMDRV_InitPerType(lpDrv, MMDRV_WAVEIN, WIDM_GETNUMDEVS); + MMDRV_InitPerType(lpDrv, MMDRV_WAVEOUT, WODM_GETNUMDEVS); + /* FIXME: if all those func calls return FALSE, + * then the driver must be unloaded + */ + + MMDrvsHi++; + + return TRUE; +} + +/************************************************************************** + * MMDRV_InitFromRegistry [internal] + */ +static BOOL MMDRV_InitFromRegistry(void) +{ + HKEY hKey; + char buffer[256]; + char* p1; + char* p2; + DWORD type, size; + BOOL ret = FALSE; + + if (RegCreateKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\WinMM", &hKey)) { + TRACE("Cannot open WinMM config key\n"); + return FALSE; + } + + size = sizeof(buffer); + if (!RegQueryValueExA(hKey, "Drivers", 0, &type, (LPVOID)buffer, &size)) { + p1 = buffer; + while (p1) { + p2 = strchr(p1, ';'); + if (p2) *p2++ = '\0'; + ret |= MMDRV_Install(p1, p1, FALSE); + p1 = p2; + } + } + + /* finish with mappers */ + size = sizeof(buffer); + if (!RegQueryValueExA(hKey, "WaveMapper", 0, &type, (LPVOID)buffer, &size)) + ret |= MMDRV_Install("wavemapper", buffer, TRUE); + size = sizeof(buffer); + if (!RegQueryValueExA(hKey, "MidiMapper", 0, &type, (LPVOID)buffer, &size)) + ret |= MMDRV_Install("midimapper", buffer, TRUE); + + RegCloseKey(hKey); + + return ret; +} + +/************************************************************************** + * MMDRV_InitHardcoded [internal] + */ +static BOOL MMDRV_InitHardcoded(void) +{ + /* first load hardware drivers */ + MMDRV_Install("wineoss.drv", "wineoss.drv", FALSE); + + /* finish with mappers */ + MMDRV_Install("wavemapper", "msacm.drv", TRUE); + MMDRV_Install("midimapper", "midimap.drv", TRUE); + + return TRUE; +} + +/************************************************************************** + * MMDRV_Init [internal] + */ +BOOL MMDRV_Init(void) +{ + /* FIXME: MMDRV_InitFromRegistry shall be MMDRV_Init in a near future */ + return MMDRV_InitFromRegistry() || MMDRV_InitHardcoded(); +} + +/****************************************************************** + * ExitPerType + * + * + */ +static BOOL MMDRV_ExitPerType(LPWINE_MM_DRIVER lpDrv, UINT type) +{ + WINE_MM_DRIVER_PART* part = &lpDrv->parts[type]; + DWORD ret; + + if (lpDrv->bIs32 && part->u.fnMessage32) { +#if 0 + ret = part->u.fnMessage32(0, DRVM_DISABLE, 0L, 0L, 0L); + TRACE("DRVM_DISABLE => %08lx\n", ret); +#endif + ret = part->u.fnMessage32(0, DRVM_EXIT, 0L, 0L, 0L); + TRACE("DRVM_EXIT => %08lx\n", ret); + } else if (!lpDrv->bIs32 && part->u.fnMessage16 && pFnCallMMDrvFunc16) { +#if 0 + ret = pFnCallMMDrvFunc16((FARPROC16)part->u.fnMessage16, + 0, DRVM_DISABLE, 0L, 0L, 0L); + TRACE("DRVM_DISABLE => %08lx\n", ret); +#endif + ret = pFnCallMMDrvFunc16((FARPROC16)part->u.fnMessage16, + 0, DRVM_EXIT, 0L, 0L, 0L); + TRACE("DRVM_EXIT => %08lx\n", ret); + } else { + return FALSE; + } + + return TRUE; +} + +/****************************************************************** + * Exit + * + * + */ +void MMDRV_Exit(void) +{ + int i; + + for (i = 0; i < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0]); i++) + { + if (MM_MLDrvs[i] != NULL) + { + FIXME("Closing while ll-driver open\n"); +#if 0 + /* FIXME: should generate a message depending on type */ + MMDRV_Free((HANDLE)(i | 0x8000), MM_MLDrvs[i]); +#endif + } + } + + /* unload driver, in reverse order of loading */ + for (i = sizeof(MMDrvs) / sizeof(MMDrvs[0]) - 1; i >= 0; i--) + { + MMDRV_ExitPerType(&MMDrvs[i], MMDRV_AUX); + MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIXER); + MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIDIIN); + MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIDIOUT); + MMDRV_ExitPerType(&MMDrvs[i], MMDRV_WAVEIN); + MMDRV_ExitPerType(&MMDrvs[i], MMDRV_WAVEOUT); + CloseDriver(MMDrvs[i].hDriver, 0, 0); + } +} diff --git a/reactos/lib/winmm/midiin.c b/reactos/lib/winmm/midiin.c deleted file mode 100644 index 29a700eaeaf..00000000000 --- a/reactos/lib/winmm/midiin.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * WinMM (midiin.c) : MIDI input related functions - * - * [8-18-2003] AG: Started adding stubs and implemented a few functions -*/ - -#include -typedef UINT *LPUINT; -#include - -#define NDEBUG -#include - - -#define IsValidMidiInHandle(hmi) \ - (((LPMidiInHandleInfo*)hmi < mi_HandleInfo) || \ - ((LPMidiInHandleInfo*)hmi >= mi_HandleInfo + (mi_HandleCount * sizeof(MidiInHandleInfo)))) - - -typedef struct MidiInDeviceInfo -{ - BOOL IsOpen; // Correct? -} MidiInDeviceInfo, *LPMidiInDeviceInfo; - -LPMidiInDeviceInfo *mi_DeviceInfo = NULL; -UINT mi_DeviceCount = 0; - - -typedef struct MidiInHandleInfo -{ - UINT DeviceID; // Needs to be first - BOOL IsOpen; -} MidiInHandleInfo, *LPMidiInHandleInfo; - - -// Array of MidiInHandleInfo structures -LPMidiInHandleInfo *mi_HandleInfo = NULL; -UINT mi_HandleCount = 0; - - -/* ------------------------------------------------------------------------- */ - -MMRESULT WINAPI midiInOpen( - LPHMIDIIN lphMidiIn, - UINT uDeviceID, - DWORD dwCallback, - DWORD dwCallbackInstance, - DWORD dwFlags) -{ - // TODO: Add device open checking and return MMSYSERR_ALLOCATED, but what - // happens for multi-client drivers? - - MidiInHandleInfo *Info = NULL; - int i; - - if (! lphMidiIn) - return MMSYSERR_INVALPARAM; - - if ((uDeviceID >= mi_DeviceCount) && (uDeviceID != MIDI_MAPPER)) - return MMSYSERR_BADDEVICEID; - - // Make sure we have a callback address if a callback is desired - if ((! dwCallback) && (dwFlags != CALLBACK_NULL)) - return MMSYSERR_INVALPARAM; - - - // Check existing handles to see if one is free - for (i = 0; i < mi_HandleCount; i ++) - if (! mi_HandleInfo[i]->IsOpen) - { - Info = mi_HandleInfo[i]; - break; - } - - // Allocate a new handle info structure - if (! Info) - { - mi_HandleCount ++; - - LPMidiInHandleInfo *Old = mi_HandleInfo; - - // File mapping stuff to replace this needed: -// if (! mi_HandleInfo) -// mi_HandleInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(MidiInHandleInfo) * mi_HandleCount); -// else -// mi_HandleInfo = HeapReAlloc(GetProcessHeap(), 0, mi_HandleInfo, sizeof(MidiInHandleInfo) * mi_HandleCount); - - if (! mi_HandleInfo) - { - mi_HandleCount --; - mi_HandleInfo = Old; - return MMSYSERR_NOMEM; // Correct? - } - - Info = mi_HandleInfo[mi_HandleCount - 1]; - } - - Info->DeviceID = uDeviceID; - - // Pretend we opened OK (really need to query device driver) - Info->IsOpen = TRUE; - - if (Info->IsOpen) - { - LPMIDICALLBACK mi_Proc = (LPMIDICALLBACK) dwCallback; - - switch(dwFlags) - { - case CALLBACK_FUNCTION : - mi_Proc((HMIDIIN) Info, MM_MOM_OPEN, dwCallbackInstance, 0, 0); - break; - - case CALLBACK_EVENT : - // Do something - break; - - case CALLBACK_THREAD : - // Do something - break; - - case CALLBACK_WINDOW : - // Do something - break; - } - } - - else - return MMSYSERR_ERROR; // Correct if can't be opened? - - // Copy the handle (really a pointer to Info): - *lphMidiIn = (HMIDIIN) Info; - - return MMSYSERR_NOERROR; -} - - -MMRESULT WINAPI midiInClose(HMIDIIN hMidiIn) -{ - LPMidiInHandleInfo Info = NULL; - - if (IsValidMidiInHandle(hMidiIn)) - return MMSYSERR_INVALHANDLE; - - // Check if buffers still queued and return MIDIERR_STILLPLAYING if so... - // TODO - - Info = (LPMidiInHandleInfo) hMidiIn; - Info->IsOpen = FALSE; - - return MMSYSERR_NOERROR; -} - - -/* ------------------------------------------------------------------------- */ - -void mi_Init() -{ - // Internal routine for initializing MIDI-Out related stuff - - // Just set up a fake device for now - // FILE MAPPING! -// mi_DeviceCount ++; -// HeapAlloc(GetProcessHeap(), 0, sizeof(MidiInDeviceInfo) * mi_DeviceCount); -} diff --git a/reactos/lib/winmm/mmsystem16.h b/reactos/lib/winmm/mmsystem16.h new file mode 100644 index 00000000000..0a79ea9d15a --- /dev/null +++ b/reactos/lib/winmm/mmsystem16.h @@ -0,0 +1,808 @@ +/* + * MMSYSTEM - Multimedia Wine Extension ... :-) + * + * Copyright (C) the Wine project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_WINE_MMSYSTEM16_H +#define __WINE_WINE_MMSYSTEM16_H + +#include "windef.h" +#include "wine/windef16.h" +#include "mmddk.h" + +#include "pshpack1.h" + +typedef UINT16 MMVERSION16; +typedef UINT16 MCIDEVICEID16; +typedef UINT16 MMRESULT16; + +typedef struct { + UINT16 wType; /* indicates the contents of the union */ + union { + DWORD ms; /* milliseconds */ + DWORD sample; /* samples */ + DWORD cb; /* byte count */ + struct { /* SMPTE */ + BYTE hour; /* hours */ + BYTE min; /* minutes */ + BYTE sec; /* seconds */ + BYTE frame; /* frames */ + BYTE fps; /* frames per second */ + BYTE dummy; /* pad */ + } smpte; + struct { /* MIDI */ + DWORD songptrpos; /* song pointer position */ + } midi; + } u; +} MMTIME16, *LPMMTIME16; + +typedef struct { + DWORD dwDCISize; + SEGPTR lpszDCISectionName; + SEGPTR lpszDCIAliasName; +} DRVCONFIGINFO16, *LPDRVCONFIGINFO16; + +/* GetDriverInfo16 references this structure, so this a struct defined + * in the Win16 API. + * GetDriverInfo has been deprecated in Win32. + */ +typedef struct +{ + UINT16 length; + HDRVR16 hDriver; + HINSTANCE16 hModule; + CHAR szAliasName[128]; +} DRIVERINFOSTRUCT16, *LPDRIVERINFOSTRUCT16; + +LRESULT WINAPI DefDriverProc16(DWORD,HDRVR16,UINT16,LPARAM,LPARAM); +HDRVR16 WINAPI OpenDriver16(LPCSTR,LPCSTR,LPARAM); +LRESULT WINAPI CloseDriver16(HDRVR16,LPARAM,LPARAM); +LRESULT WINAPI SendDriverMessage16(HDRVR16,UINT16,LPARAM,LPARAM); +HMODULE16 WINAPI GetDriverModuleHandle16(HDRVR16); +HDRVR16 WINAPI GetNextDriver16(HDRVR16,DWORD); +BOOL16 WINAPI GetDriverInfo16(HDRVR16,DRIVERINFOSTRUCT16 *); + +typedef void (CALLBACK *LPDRVCALLBACK16) (HDRVR16,UINT16,DWORD,DWORD,DWORD); +typedef LPDRVCALLBACK16 LPWAVECALLBACK16; + +UINT16 WINAPI mmsystemGetVersion16(void); +BOOL16 WINAPI sndPlaySound16(LPCSTR,UINT16); + +typedef struct { + WORD wMid; /* manufacturer ID */ + WORD wPid; /* product ID */ + MMVERSION16 vDriverVersion; /* version of the driver */ + CHAR szPname[MAXPNAMELEN]; /* product name (0 terminated string) */ + DWORD dwFormats; /* formats supported */ + WORD wChannels; /* number of sources supported */ + DWORD dwSupport; /* functionality supported by driver */ +} WAVEOUTCAPS16, *LPWAVEOUTCAPS16; + +typedef struct { + WORD wMid; /* manufacturer ID */ + WORD wPid; /* product ID */ + MMVERSION16 vDriverVersion; /* version of the driver */ + CHAR szPname[MAXPNAMELEN]; /* product name (0 terminated string) */ + DWORD dwFormats; /* formats supported */ + WORD wChannels; /* number of channels supported */ +} WAVEINCAPS16, *LPWAVEINCAPS16; + +typedef struct { + HWAVE16 hWave; + LPWAVEFORMATEX lpFormat; + DWORD dwCallback; + DWORD dwInstance; + UINT16 uMappedDeviceID; + DWORD dnDevNode; +} WAVEOPENDESC16, *LPWAVEOPENDESC16; + +UINT16 WINAPI waveOutGetNumDevs16(void); +UINT16 WINAPI waveOutGetDevCaps16(UINT16,LPWAVEOUTCAPS16,UINT16); +UINT16 WINAPI waveOutGetVolume16(UINT16,DWORD*); +UINT16 WINAPI waveOutSetVolume16(UINT16,DWORD); +UINT16 WINAPI waveOutGetErrorText16(UINT16,LPSTR,UINT16); +UINT16 WINAPI waveOutOpen16(HWAVEOUT16*,UINT16,const LPWAVEFORMATEX,DWORD,DWORD,DWORD); +UINT16 WINAPI waveOutClose16(HWAVEOUT16); +UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16,SEGPTR,UINT16); +UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16,SEGPTR,UINT16); +UINT16 WINAPI waveOutWrite16(HWAVEOUT16,WAVEHDR*,UINT16); +UINT16 WINAPI waveOutPause16(HWAVEOUT16); +UINT16 WINAPI waveOutRestart16(HWAVEOUT16); +UINT16 WINAPI waveOutReset16(HWAVEOUT16); +UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16); +UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16,LPMMTIME16,UINT16); +UINT16 WINAPI waveOutGetPitch16(HWAVEOUT16,DWORD*); +UINT16 WINAPI waveOutSetPitch16(HWAVEOUT16,DWORD); +UINT16 WINAPI waveOutGetPlaybackRate16(HWAVEOUT16,DWORD*); +UINT16 WINAPI waveOutSetPlaybackRate16(HWAVEOUT16,DWORD); +UINT16 WINAPI waveOutGetID16(HWAVEOUT16,UINT16*); +DWORD WINAPI waveOutMessage16(HWAVEOUT16,UINT16,DWORD,DWORD); +UINT16 WINAPI waveInGetNumDevs16(void); +UINT16 WINAPI waveInGetDevCaps16(UINT16,LPWAVEINCAPS16,UINT16); +UINT16 WINAPI waveInGetErrorText16(UINT16,LPSTR,UINT16); +UINT16 WINAPI waveInOpen16(HWAVEIN16*,UINT16,const LPWAVEFORMATEX,DWORD,DWORD,DWORD); +UINT16 WINAPI waveInClose16(HWAVEIN16); +UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16,SEGPTR,UINT16); +UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16,SEGPTR,UINT16); +UINT16 WINAPI waveInAddBuffer16(HWAVEIN16,WAVEHDR*,UINT16); +UINT16 WINAPI waveInStart16(HWAVEIN16); +UINT16 WINAPI waveInStop16(HWAVEIN16); +UINT16 WINAPI waveInReset16(HWAVEIN16); +UINT16 WINAPI waveInGetPosition16(HWAVEIN16,LPMMTIME16,UINT16); +UINT16 WINAPI waveInGetID16(HWAVEIN16,UINT16*); +DWORD WINAPI waveInMessage16(HWAVEIN16,UINT16,DWORD,DWORD); + +typedef LPDRVCALLBACK16 LPMIDICALLBACK16; + +typedef struct { + WORD wMid; /* manufacturer ID */ + WORD wPid; /* product ID */ + MMVERSION16 vDriverVersion; /* version of the driver */ + CHAR szPname[MAXPNAMELEN];/* product name (NULL terminated string) */ + WORD wTechnology; /* type of device */ + WORD wVoices; /* # of voices (internal synth only) */ + WORD wNotes; /* max # of notes (internal synth only) */ + WORD wChannelMask; /* channels used (internal synth only) */ + DWORD dwSupport; /* functionality supported by driver */ +} MIDIOUTCAPS16, *LPMIDIOUTCAPS16; + +typedef struct { + WORD wMid; /* manufacturer ID */ + WORD wPid; /* product ID */ + MMVERSION16 vDriverVersion; /* version of the driver */ + CHAR szPname[MAXPNAMELEN];/* product name (NULL terminated string) */ + DWORD dwSupport; /* included in win95 and higher */ +} MIDIINCAPS16, *LPMIDIINCAPS16; + +typedef struct midihdr16_tag { + LPSTR lpData; /* pointer to locked data block */ + DWORD dwBufferLength; /* length of data in data block */ + DWORD dwBytesRecorded;/* used for input only */ + DWORD dwUser; /* for client's use */ + DWORD dwFlags; /* assorted flags (see defines) */ + struct midihdr16_tag *lpNext; /* reserved for driver */ + DWORD reserved; /* reserved for driver */ +} MIDIHDR16, *LPMIDIHDR16; + +typedef struct { + HMIDI16 hMidi; + DWORD dwCallback; + DWORD dwInstance; + UINT16 reserved; + DWORD dnDevNode; + DWORD cIds; + MIDIOPENSTRMID rgIds; +} MIDIOPENDESC16, *LPMIDIOPENDESC16; + +UINT16 WINAPI midiOutGetNumDevs16(void); +UINT16 WINAPI midiOutGetDevCaps16(UINT16,LPMIDIOUTCAPS16,UINT16); +UINT16 WINAPI midiOutGetVolume16(UINT16,DWORD*); +UINT16 WINAPI midiOutSetVolume16(UINT16,DWORD); +UINT16 WINAPI midiOutGetErrorText16(UINT16,LPSTR,UINT16); +UINT16 WINAPI midiOutOpen16(HMIDIOUT16*,UINT16,DWORD,DWORD,DWORD); +UINT16 WINAPI midiOutClose16(HMIDIOUT16); +UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16,SEGPTR,UINT16); +UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16,SEGPTR,UINT16); +UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16,DWORD); +UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16,MIDIHDR16*,UINT16); +UINT16 WINAPI midiOutReset16(HMIDIOUT16); +UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16,UINT16,WORD*,UINT16); +UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16,UINT16,WORD*,UINT16); +UINT16 WINAPI midiOutGetID16(HMIDIOUT16,UINT16*); +DWORD WINAPI midiOutMessage16(HMIDIOUT16,UINT16,DWORD,DWORD); +UINT16 WINAPI midiInGetNumDevs16(void); +UINT16 WINAPI midiInGetDevCaps16(UINT16,LPMIDIINCAPS16,UINT16); +UINT16 WINAPI midiInGetErrorText16(UINT16,LPSTR,UINT16); +UINT16 WINAPI midiInOpen16(HMIDIIN16*,UINT16,DWORD,DWORD,DWORD); +UINT16 WINAPI midiInClose16(HMIDIIN16); +UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16,SEGPTR,UINT16); +UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16,SEGPTR,UINT16); +UINT16 WINAPI midiInAddBuffer16(HMIDIIN16,MIDIHDR16*,UINT16); +UINT16 WINAPI midiInStart16(HMIDIIN16); +UINT16 WINAPI midiInStop16(HMIDIIN16); +UINT16 WINAPI midiInReset16(HMIDIIN16); +UINT16 WINAPI midiInGetID16(HMIDIIN16,UINT16*); +DWORD WINAPI midiInMessage16(HMIDIIN16,UINT16,DWORD,DWORD); +MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hms); +MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16*,LPUINT16,DWORD,DWORD,DWORD,DWORD); +MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16,LPMIDIHDR16,UINT16); +MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16); +MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16,LPMMTIME16,UINT16); +MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16,LPBYTE,DWORD); +MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16); +MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16); + +typedef struct { + WORD wMid; /* manufacturer ID */ + WORD wPid; /* product ID */ + MMVERSION16 vDriverVersion; /* version of the driver */ + CHAR szPname[MAXPNAMELEN]; /* product name (NULL terminated string) */ + WORD wTechnology; /* type of device */ + DWORD dwSupport; /* functionality supported by driver */ +} AUXCAPS16, *LPAUXCAPS16; + +typedef void (CALLBACK *LPTIMECALLBACK16)(UINT16,UINT16,DWORD,DWORD,DWORD); + +typedef struct { + UINT16 wPeriodMin; /* minimum period supported */ + UINT16 wPeriodMax; /* maximum period supported */ +} TIMECAPS16,*LPTIMECAPS16; + +typedef struct { + WORD wMid; /* manufacturer ID */ + WORD wPid; /* product ID */ + char szPname[MAXPNAMELEN]; /* product name (NULL terminated string) */ + UINT16 wXmin; /* minimum x position value */ + UINT16 wXmax; /* maximum x position value */ + UINT16 wYmin; /* minimum y position value */ + UINT16 wYmax; /* maximum y position value */ + UINT16 wZmin; /* minimum z position value */ + UINT16 wZmax; /* maximum z position value */ + UINT16 wNumButtons; /* number of buttons */ + UINT16 wPeriodMin; /* minimum message period when captured */ + UINT16 wPeriodMax; /* maximum message period when captured */ + /* win95,nt4 additions: */ + UINT16 wRmin; /* minimum r position value */ + UINT16 wRmax; /* maximum r position value */ + UINT16 wUmin; /* minimum u (5th axis) position value */ + UINT16 wUmax; /* maximum u (5th axis) position value */ + UINT16 wVmin; /* minimum v (6th axis) position value */ + UINT16 wVmax; /* maximum v (6th axis) position value */ + UINT16 wCaps; /* joystick capabilites */ + UINT16 wMaxAxes; /* maximum number of axes supported */ + UINT16 wNumAxes; /* number of axes in use */ + UINT16 wMaxButtons; /* maximum number of buttons supported */ + CHAR szRegKey[MAXPNAMELEN]; /* registry key */ + CHAR szOEMVxD[MAX_JOYSTICKOEMVXDNAME]; /* OEM VxD in use */ +} JOYCAPS16, *LPJOYCAPS16; + +typedef struct { + UINT16 wXpos; /* x position */ + UINT16 wYpos; /* y position */ + UINT16 wZpos; /* z position */ + UINT16 wButtons; /* button states */ +} JOYINFO16, *LPJOYINFO16; + +typedef struct { + WORD wMid; /* manufacturer id */ + WORD wPid; /* product id */ + MMVERSION16 vDriverVersion; /* version of the driver */ + CHAR szPname[MAXPNAMELEN]; /* product name */ + DWORD fdwSupport; /* misc. support bits */ + DWORD cDestinations; /* count of destinations */ +} MIXERCAPS16,*LPMIXERCAPS16; + +typedef struct tMIXEROPENDESC16 +{ + HMIXEROBJ16 hmx; + LPVOID pReserved0; + DWORD dwCallback; + DWORD dwInstance; +} MIXEROPENDESC16, *LPMIXEROPENDESC16; + +typedef struct { + DWORD cbStruct; /* size of MIXERLINE structure */ + DWORD dwDestination; /* zero based destination index */ + DWORD dwSource; /* zero based source index (if source) */ + DWORD dwLineID; /* unique line id for mixer device */ + DWORD fdwLine; /* state/information about line */ + DWORD dwUser; /* driver specific information */ + DWORD dwComponentType; /* component type line connects to */ + DWORD cChannels; /* number of channels line supports */ + DWORD cConnections; /* number of connections [possible] */ + DWORD cControls; /* number of controls at this line */ + CHAR szShortName[MIXER_SHORT_NAME_CHARS]; + CHAR szName[MIXER_LONG_NAME_CHARS]; + struct { + DWORD dwType; /* MIXERLINE_TARGETTYPE_xxxx */ + DWORD dwDeviceID; /* target device ID of device type */ + WORD wMid; /* of target device */ + WORD wPid; /* " */ + MMVERSION16 vDriverVersion; /* " */ + CHAR szPname[MAXPNAMELEN]; /* " */ + } Target; +} MIXERLINE16, *LPMIXERLINE16; + +typedef struct { + DWORD cbStruct; /* size in bytes of MIXERCONTROL */ + DWORD dwControlID; /* unique control id for mixer device */ + DWORD dwControlType; /* MIXERCONTROL_CONTROLTYPE_xxx */ + DWORD fdwControl; /* MIXERCONTROL_CONTROLF_xxx */ + DWORD cMultipleItems; /* if MIXERCONTROL_CONTROLF_MULTIPLE set */ + CHAR szShortName[MIXER_SHORT_NAME_CHARS]; + CHAR szName[MIXER_LONG_NAME_CHARS]; + union { + struct { + LONG lMinimum; /* signed minimum for this control */ + LONG lMaximum; /* signed maximum for this control */ + } DUMMYSTRUCTNAME; + struct { + DWORD dwMinimum; /* unsigned minimum for this control */ + DWORD dwMaximum; /* unsigned maximum for this control */ + } DUMMYSTRUCTNAME1; + DWORD dwReserved[6]; + } Bounds; + union { + DWORD cSteps; /* # of steps between min & max */ + DWORD cbCustomData; /* size in bytes of custom data */ + DWORD dwReserved[6]; /* !!! needed? we have cbStruct.... */ + } Metrics; +} MIXERCONTROL16, *LPMIXERCONTROL16; + +typedef struct { + DWORD cbStruct; /* size in bytes of MIXERLINECONTROLS */ + DWORD dwLineID; /* line id (from MIXERLINE.dwLineID) */ + union { + DWORD dwControlID; /* MIXER_GETLINECONTROLSF_ONEBYID */ + DWORD dwControlType; /* MIXER_GETLINECONTROLSF_ONEBYTYPE */ + } DUMMYUNIONNAME; + DWORD cControls; /* count of controls pmxctrl points to */ + DWORD cbmxctrl; /* size in bytes of _one_ MIXERCONTROL */ + SEGPTR pamxctrl; /* pointer to first MIXERCONTROL array */ +} MIXERLINECONTROLS16, *LPMIXERLINECONTROLS16; + +typedef struct { + DWORD cbStruct; /* size in bytes of MIXERCONTROLDETAILS */ + DWORD dwControlID; /* control id to get/set details on */ + DWORD cChannels; /* number of channels in paDetails array */ + union { + HWND16 hwndOwner; /* for MIXER_SETCONTROLDETAILSF_CUSTOM */ + DWORD cMultipleItems; /* if _MULTIPLE, the number of items per channel */ + } DUMMYUNIONNAME; + DWORD cbDetails; /* size of _one_ details_XX struct */ + LPVOID paDetails; /* pointer to array of details_XX structs */ +} MIXERCONTROLDETAILS16,*LPMIXERCONTROLDETAILS16; + +typedef struct { + DWORD dwParam1; + DWORD dwParam2; + CHAR szName[MIXER_LONG_NAME_CHARS]; +} MIXERCONTROLDETAILS_LISTTEXT16,*LPMIXERCONTROLDETAILS_LISTTEXT16; + +typedef LRESULT (CALLBACK *LPMMIOPROC16)(LPSTR lpmmioinfo,UINT16 uMessage, + LPARAM lParam1,LPARAM lParam2); + +typedef struct { + DWORD dwFlags; /* general status flags */ + FOURCC fccIOProc; /* pointer to I/O procedure */ + LPMMIOPROC16 pIOProc; /* pointer to I/O procedure */ + UINT16 wErrorRet; /* place for error to be returned */ + HTASK16 hTask; /* alternate local task */ + /* fields maintained by MMIO functions during buffered I/O */ + LONG cchBuffer; /* size of I/O buffer (or 0L) */ + HPSTR pchBuffer; /* start of I/O buffer (or NULL) */ + HPSTR pchNext; /* pointer to next byte to read/write */ + HPSTR pchEndRead; /* pointer to last valid byte to read */ + HPSTR pchEndWrite; /* pointer to last byte to write */ + LONG lBufOffset; /* disk offset of start of buffer */ + /* fields maintained by I/O procedure */ + LONG lDiskOffset; /* disk offset of next read or write */ + DWORD adwInfo[3]; /* data specific to type of MMIOPROC */ + /* other fields maintained by MMIO */ + DWORD dwReserved1; /* reserved for MMIO use */ + DWORD dwReserved2; /* reserved for MMIO use */ + HMMIO16 hmmio; /* handle to open file */ +} MMIOINFO16, *LPMMIOINFO16; + +typedef UINT16 (CALLBACK *YIELDPROC16)(UINT16,DWORD); + +UINT16 WINAPI auxGetNumDevs16(void); +UINT16 WINAPI auxGetDevCaps16 (UINT16,LPAUXCAPS16,UINT16); +UINT16 WINAPI auxSetVolume16(UINT16,DWORD); +UINT16 WINAPI auxGetVolume16(UINT16,LPDWORD); +DWORD WINAPI auxOutMessage16(UINT16,UINT16,DWORD,DWORD); +MMRESULT16 WINAPI timeGetSystemTime16(LPMMTIME16,UINT16); +MMRESULT16 WINAPI timeSetEvent16(UINT16,UINT16,LPTIMECALLBACK16,DWORD,UINT16); +MMRESULT16 WINAPI timeKillEvent16(UINT16); +MMRESULT16 WINAPI timeGetDevCaps16(LPTIMECAPS16,UINT16); +MMRESULT16 WINAPI timeBeginPeriod16(UINT16); +MMRESULT16 WINAPI timeEndPeriod16(UINT16); +MMRESULT16 WINAPI joyGetDevCaps16 (UINT16,LPJOYCAPS16,UINT16); +UINT16 WINAPI joyGetNumDevs16(void); +MMRESULT16 WINAPI joyGetPos16(UINT16,LPJOYINFO16); +MMRESULT16 WINAPI joyGetPosEx16(UINT16,LPJOYINFOEX); +MMRESULT16 WINAPI joyGetThreshold16(UINT16,UINT16*); +MMRESULT16 WINAPI joyReleaseCapture16(UINT16); +MMRESULT16 WINAPI joySetCapture16(HWND16,UINT16,UINT16,BOOL16); +MMRESULT16 WINAPI joySetThreshold16(UINT16,UINT16); +UINT16 WINAPI mixerGetNumDevs16(void); +UINT16 WINAPI mixerOpen16(LPHMIXER16,UINT16,DWORD,DWORD,DWORD); +UINT16 WINAPI mixerClose16(HMIXER16); +DWORD WINAPI mixerMessage16(HMIXER16,UINT16,DWORD,DWORD); +UINT16 WINAPI mixerGetDevCaps16(UINT16,LPMIXERCAPS16,UINT16); +UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16,LPMIXERLINE16,DWORD); +UINT16 WINAPI mixerGetID16(HMIXEROBJ16,LPUINT16,DWORD); +UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16,LPMIXERLINECONTROLS16,DWORD); +UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16,LPMIXERCONTROLDETAILS16,DWORD); +UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16,LPMIXERCONTROLDETAILS16,DWORD); +LPMMIOPROC16 WINAPI mmioInstallIOProc16(FOURCC,LPMMIOPROC16,DWORD); +FOURCC WINAPI mmioStringToFOURCC16(LPCSTR,UINT16); +HMMIO16 WINAPI mmioOpen16(LPSTR,MMIOINFO16*,DWORD); +UINT16 WINAPI mmioRename16(LPCSTR,LPCSTR,MMIOINFO16*,DWORD); +MMRESULT16 WINAPI mmioClose16(HMMIO16,UINT16); +LONG WINAPI mmioRead16(HMMIO16,HPSTR,LONG); +LONG WINAPI mmioWrite16(HMMIO16,HPCSTR,LONG); +LONG WINAPI mmioSeek16(HMMIO16,LONG,INT16); +MMRESULT16 WINAPI mmioGetInfo16(HMMIO16,MMIOINFO16*,UINT16); +MMRESULT16 WINAPI mmioSetInfo16(HMMIO16,const MMIOINFO16*,UINT16); +UINT16 WINAPI mmioSetBuffer16(HMMIO16,LPSTR,LONG,UINT16); +UINT16 WINAPI mmioFlush16(HMMIO16,UINT16); +UINT16 WINAPI mmioAdvance16(HMMIO16,MMIOINFO16*,UINT16); +LONG WINAPI mmioSendMessage16(HMMIO16,UINT16,LPARAM,LPARAM); +UINT16 WINAPI mmioDescend16(HMMIO16,MMCKINFO*,const MMCKINFO*,UINT16); +UINT16 WINAPI mmioAscend16(HMMIO16,MMCKINFO*,UINT16); +UINT16 WINAPI mmioCreateChunk16(HMMIO16,MMCKINFO*,UINT16); +DWORD WINAPI mciSendCommand16(UINT16,UINT16,DWORD,DWORD); +DWORD WINAPI mciSendString16(LPCSTR,LPSTR,UINT16,HWND16); +UINT16 WINAPI mciGetDeviceID16(LPCSTR); +UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD,LPCSTR); +BOOL16 WINAPI mciGetErrorString16 (DWORD,LPSTR,UINT16); +BOOL16 WINAPI mciSetYieldProc16(UINT16,YIELDPROC16,DWORD); +HTASK16 WINAPI mciGetCreatorTask16(UINT16); +YIELDPROC16 WINAPI mciGetYieldProc16(UINT16,DWORD*); +DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID); +BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD dwData); +UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID); +BOOL16 WINAPI mciDriverNotify16(HWND16 hwndCallback, UINT16 uDeviceID, + UINT16 uStatus); +UINT16 WINAPI mciLoadCommandResource16(HINSTANCE16 hInstance, + LPCSTR lpResName, UINT16 uType); +BOOL16 WINAPI mciFreeCommandResource16(UINT16 uTable); + +HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt); +void WINAPI mmTaskBlock16(HINSTANCE16 hInst); +LRESULT WINAPI mmTaskSignal16(HTASK16 ht); +void WINAPI mmTaskYield16(void); +LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE16 lpHndl, + DWORD dwPmt, DWORD dwFlags); +void WINAPI mmThreadSignal16(HANDLE16 hndl); +void WINAPI mmThreadBlock16(HANDLE16 hndl); +HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl); +BOOL16 WINAPI mmThreadIsValid16(HANDLE16 hndl); +BOOL16 WINAPI mmThreadIsCurrent16(HANDLE16 hndl); + +BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HANDLE16 hDev, + WORD wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2); + +typedef struct { + DWORD dwCallback; + WORD wDeviceID; + WORD wReserved0; + SEGPTR lpstrDeviceType; + SEGPTR lpstrElementName; + SEGPTR lpstrAlias; +} MCI_OPEN_PARMS16, *LPMCI_OPEN_PARMS16; + +typedef struct { + DWORD dwCallback; + SEGPTR lpstrReturn; + DWORD dwRetSize; +} MCI_INFO_PARMS16, *LPMCI_INFO_PARMS16; + +typedef struct { + DWORD dwCallback; + SEGPTR lpstrReturn; + DWORD dwRetSize; + DWORD dwNumber; + WORD wDeviceType; + WORD wReserved0; +} MCI_SYSINFO_PARMS16, *LPMCI_SYSINFO_PARMS16; + +typedef struct { + DWORD dwCallback; + UINT16 nVirtKey; + WORD wReserved0; + HWND16 hwndBreak; + WORD wReserved1; +} MCI_BREAK_PARMS16, *LPMCI_BREAK_PARMS16; + +typedef struct { + DWORD dwCallback; + LPCSTR lpfilename; +} MCI_LOAD_PARMS16, *LPMCI_LOAD_PARMS16; + +typedef struct { + DWORD dwCallback; + SEGPTR lpstrCommand; +} MCI_VD_ESCAPE_PARMS16, *LPMCI_VD_ESCAPE_PARMS16; + +typedef struct { + UINT16 wDeviceID; /* device ID */ + SEGPTR lpstrParams; /* parameter string for entry in SYSTEM.INI */ + UINT16 wCustomCommandTable; /* custom command table (0xFFFF if none) + * filled in by the driver */ + UINT16 wType; /* driver type (filled in by the driver) */ +} MCI_OPEN_DRIVER_PARMS16, *LPMCI_OPEN_DRIVER_PARMS16; + +typedef struct { + DWORD dwCallback; + MCIDEVICEID16 wDeviceID; + WORD wReserved0; + SEGPTR lpstrDeviceType; + SEGPTR lpstrElementName; + SEGPTR lpstrAlias; + DWORD dwBufferSeconds; +} MCI_WAVE_OPEN_PARMS16, *LPMCI_WAVE_OPEN_PARMS16; + +typedef struct { + DWORD dwCallback; + DWORD dwTimeFormat; + DWORD dwAudio; + UINT16 wInput; + UINT16 wReserved0; + UINT16 wOutput; + UINT16 wReserved1; + UINT16 wFormatTag; + UINT16 wReserved2; + UINT16 nChannels; + UINT16 wReserved3; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + UINT16 nBlockAlign; + UINT16 wReserved4; + UINT16 wBitsPerSample; + UINT16 wReserved5; +} MCI_WAVE_SET_PARMS16, * LPMCI_WAVE_SET_PARMS16; + +typedef struct { + DWORD dwCallback; + UINT16 wDeviceID; + UINT16 wReserved0; + SEGPTR lpstrDeviceType; + SEGPTR lpstrElementName; + SEGPTR lpstrAlias; + DWORD dwStyle; + HWND16 hWndParent; + UINT16 wReserved1; +} MCI_ANIM_OPEN_PARMS16, *LPMCI_ANIM_OPEN_PARMS16; + +typedef struct { + DWORD dwCallback; + HWND16 hWnd; + WORD wReserved1; + WORD nCmdShow; + WORD wReserved2; + LPCSTR lpstrText; +} MCI_ANIM_WINDOW_PARMS16, *LPMCI_ANIM_WINDOW_PARMS16; + +typedef struct { + DWORD dwCallback; +#ifdef MCI_USE_OFFEXT + POINT16 ptOffset; + POINT16 ptExtent; +#else /* ifdef MCI_USE_OFFEXT */ + RECT16 rc; +#endif /* ifdef MCI_USE_OFFEXT */ +} MCI_ANIM_RECT_PARMS16, *LPMCI_ANIM_RECT_PARMS16; + +typedef struct { + DWORD dwCallback; + RECT16 rc; + HDC16 hDC; +} MCI_ANIM_UPDATE_PARMS16, *LPMCI_ANIM_UPDATE_PARMS16; + +typedef struct { + DWORD dwCallback; + MCIDEVICEID16 wDeviceID; + WORD wReserved0; + LPCSTR lpstrDeviceType; + LPCSTR lpstrElementName; + LPCSTR lpstrAlias; + DWORD dwStyle; + HWND16 hWndParent; + WORD wReserved1; +} MCI_OVLY_OPEN_PARMS16, *LPMCI_OVLY_OPEN_PARMS16; + +typedef struct { + DWORD dwCallback; + HWND16 hWnd; + WORD wReserved1; + UINT16 nCmdShow; + WORD wReserved2; + LPCSTR lpstrText; +} MCI_OVLY_WINDOW_PARMS16, *LPMCI_OVLY_WINDOW_PARMS16; + +typedef struct { + DWORD dwCallback; +#ifdef MCI_USE_OFFEXT + POINT16 ptOffset; + POINT16 ptExtent; +#else /* ifdef MCI_USE_OFFEXT */ + RECT16 rc; +#endif /* ifdef MCI_USE_OFFEXT */ +} MCI_OVLY_RECT_PARMS16, *LPMCI_OVLY_RECT_PARMS16; + +typedef struct { + DWORD dwCallback; + LPCSTR lpfilename; + RECT16 rc; +} MCI_OVLY_SAVE_PARMS16, *LPMCI_OVLY_SAVE_PARMS16; + +typedef struct { + DWORD dwCallback; + LPCSTR lpfilename; + RECT16 rc; +} MCI_OVLY_LOAD_PARMS16, *LPMCI_OVLY_LOAD_PARMS16; + +/* from digitalv / 16 bit */ +typedef struct { + DWORD dwCallback; + RECT16 rc; +} MCI_DGV_RECT_PARMS16, *LPMCI_DGV_RECT_PARMS16; + +typedef struct { + DWORD dwCallback; + LPSTR lpstrFileName; + RECT16 rc; +} MCI_DGV_CAPTURE_PARMS16, *LPMCI_DGV_CAPTURE_PARMS16; + +typedef struct { + DWORD dwCallback; + DWORD dwFrom; + DWORD dwTo; + RECT16 rc; + DWORD dwAudioStream; + DWORD dwVideoStream; +} MCI_DGV_COPY_PARMS16, *LPMCI_DGV_COPY_PARMS16; + +typedef struct { + DWORD dwCallback; + DWORD dwFrom; + DWORD dwTo; + RECT16 rc; + DWORD dwAudioStream; + DWORD dwVideoStream; +} MCI_DGV_CUT_PARMS16, * LPMCI_DGV_CUT_PARMS16; + +typedef struct { + DWORD dwCallback; + DWORD dwFrom; + DWORD dwTo; + RECT16 rc; + DWORD dwAudioStream; + DWORD dwVideoStream; +} MCI_DGV_DELETE_PARMS16, * LPMCI_DGV_DELETE_PARMS16; + +typedef MCI_DGV_RECT_PARMS16 MCI_DGV_FREEZE_PARMS16, * LPMCI_DGV_FREEZE_PARMS16; + +typedef struct { + DWORD dwCallback; + LPSTR lpstrReturn; + DWORD dwRetSize; + DWORD dwItem; +} MCI_DGV_INFO_PARMS16, * LPMCI_DGV_INFO_PARMS16; + +typedef struct { + DWORD dwCallback; + LPSTR lpstrReturn; + DWORD dwLength; + DWORD dwNumber; + DWORD dwItem; + LPSTR lpstrAlgorithm; +} MCI_DGV_LIST_PARMS16, *LPMCI_DGV_LIST_PARMS16; + +typedef MCI_LOAD_PARMS16 MCI_DGV_LOAD_PARMS16 , * LPMCI_DGV_LOAD_PARMS16; + +typedef struct { + DWORD dwCallback; + UINT16 wDeviceID; + UINT16 wReserved0; + LPSTR lpstrDeviceType; + LPSTR lpstrElementName; + LPSTR lpstrAlias; + DWORD dwStyle; + HWND16 hWndParent; + UINT16 wReserved1; +} MCI_DGV_OPEN_PARMS16, *LPMCI_DGV_OPEN_PARMS16; + +typedef struct { + DWORD dwCallback; + DWORD dwTo; + RECT16 rc; + DWORD dwAudioStream; + DWORD dwVideoStream; +} MCI_DGV_PASTE_PARMS16, * LPMCI_DGV_PASTE_PARMS16; + +typedef MCI_DGV_RECT_PARMS16 MCI_DGV_PUT_PARMS16, * LPMCI_DGV_PUT_PARMS16; + +typedef struct { + DWORD dwCallback; + DWORD dwItem; + LPSTR lpstrName; + DWORD lpstrAlgorithm; + DWORD dwHandle; +} MCI_DGV_QUALITY_PARMS16, *LPMCI_DGV_QUALITY_PARMS16; + +typedef struct { + DWORD dwCallback; + DWORD dwFrom; + DWORD dwTo; + RECT16 rc; + DWORD dwAudioStream; + DWORD dwVideoStream; +} MCI_DGV_RECORD_PARMS16, * LPMCI_DGV_RECORD_PARMS16; + +typedef struct { + DWORD dwCallback; + LPSTR lpstrPath; + DWORD dwSize; +} MCI_DGV_RESERVE_PARMS16, *LPMCI_DGV_RESERVE_PARMS16A; + +typedef struct { + DWORD dwCallback; + LPSTR lpstrFileName; + RECT16 rc; +} MCI_DGV_RESTORE_PARMS16, *LPMCI_DGV_RESTORE_PARMS16; + +typedef struct { + DWORD dwCallback; + LPSTR lpstrFileName; + RECT16 rc; +} MCI_DGV_SAVE_PARMS16, *LPMCI_DGV_SAVE_PARMS16; + +typedef struct { + DWORD dwCallback; + DWORD dwItem; + DWORD dwValue; + DWORD dwOver; + LPSTR lpstrAlgorithm; + LPSTR lpstrQuality; +} MCI_DGV_SETAUDIO_PARMS16, *LPMCI_DGV_SETAUDIO_PARMS16; + +typedef struct { + DWORD dwCallback; + DWORD dwItem; + DWORD dwValue; + DWORD dwOver; + LPSTR lpstrAlgorithm; + LPSTR lpstrQuality; + DWORD dwSourceNumber; +} MCI_DGV_SETVIDEO_PARMS16, *LPMCI_DGV_SETVIDEO_PARMS16; + +typedef struct { + DWORD dwCallback; + DWORD dwReturn; + DWORD dwItem; + DWORD dwTrack; + SEGPTR lpstrDrive; + DWORD dwReference; +} MCI_DGV_STATUS_PARMS16, *LPMCI_DGV_STATUS_PARMS16; + +typedef struct { + DWORD dwCallback; + RECT16 rc; + HDC16 hDC; + UINT16 wReserved0; +} MCI_DGV_UPDATE_PARMS16, * LPMCI_DGV_UPDATE_PARMS16; + +typedef MCI_DGV_RECT_PARMS16 MCI_DGV_UNFREEZE_PARMS16, * LPMCI_DGV_UNFREEZE_PARMS16; + +typedef MCI_DGV_RECT_PARMS16 MCI_DGV_WHERE_PARMS16, * LPMCI_DGV_WHERE_PARMS16; + +typedef struct { + DWORD dwCallback; + HWND16 hWnd; + UINT16 wReserved1; + UINT16 nCmdShow; + UINT16 wReserved2; + LPSTR lpstrText; +} MCI_DGV_WINDOW_PARMS16, *LPMCI_DGV_WINDOW_PARMS16; + +#include "poppack.h" + +#endif /* __WINE_WINE_MMSYSTEM16_H */ diff --git a/reactos/lib/winmm/winemm.h b/reactos/lib/winmm/winemm.h new file mode 100644 index 00000000000..82d1e4a872c --- /dev/null +++ b/reactos/lib/winmm/winemm.h @@ -0,0 +1,351 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/***************************************************************************** + * Copyright 1998, Luiz Otavio L. Zorzella + * 1999, Eric Pouech + * + * Purpose: multimedia declarations (internal to WINMM & MMSYSTEM DLLs) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + ***************************************************************************** + */ + +#include + +#ifdef __WINE_FOR_REACTOS__ + +#include +// AG: This is most likely BAD: +#define MMTIME16 MMTIME +#define LPMMTIME16 LPMMTIME + +#else + +#include "wine/mmsystem16.h" +#include "wownt32.h" + +#endif + + +typedef DWORD (WINAPI *MessageProc16)(UINT16 wDevID, UINT16 wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2); +typedef DWORD (WINAPI *MessageProc32)(UINT wDevID, UINT wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2); + +typedef enum { + WINMM_MAP_NOMEM, /* ko, memory problem */ + WINMM_MAP_MSGERROR, /* ko, unknown message */ + WINMM_MAP_OK, /* ok, no memory allocated. to be sent to the proc. */ + WINMM_MAP_OKMEM, /* ok, some memory allocated, need to call UnMapMsg. to be sent to the proc. */ +} WINMM_MapType; + +/* Who said goofy boy ? */ +#define WINE_DI_MAGIC 0x900F1B01 + +typedef struct tagWINE_DRIVER +{ + DWORD dwMagic; + /* as usual LPWINE_DRIVER == hDriver32 */ + DWORD dwFlags; + union { + struct { + HMODULE hModule; + DRIVERPROC lpDrvProc; + DWORD dwDriverID; + } d32; + struct { + HDRVR16 hDriver16; + } d16; + } d; + struct tagWINE_DRIVER* lpPrevItem; + struct tagWINE_DRIVER* lpNextItem; +} WINE_DRIVER, *LPWINE_DRIVER; + +typedef DWORD (CALLBACK *WINEMM_msgFunc16)(UINT16, WORD, DWORD, DWORD, DWORD); +typedef DWORD (CALLBACK *WINEMM_msgFunc32)(UINT , UINT, DWORD, DWORD, DWORD); + +/* for each loaded driver and each known type of driver, this structure contains + * the information needed to access it + */ +typedef struct tagWINE_MM_DRIVER_PART { + int nIDMin; /* lower bound of global indexes for this type */ + int nIDMax; /* hhigher bound of global indexes for this type */ + union { + WINEMM_msgFunc32 fnMessage32; /* pointer to fonction */ + WINEMM_msgFunc16 fnMessage16; + } u; +} WINE_MM_DRIVER_PART; + +#define MMDRV_AUX 0 +#define MMDRV_MIXER 1 +#define MMDRV_MIDIIN 2 +#define MMDRV_MIDIOUT 3 +#define MMDRV_WAVEIN 4 +#define MMDRV_WAVEOUT 5 +#define MMDRV_MAX 6 + +/* each low-level .drv will be associated with an instance of this structure */ +typedef struct tagWINE_MM_DRIVER { + HDRVR hDriver; + LPSTR drvname; /* name of the driver */ + BOOL bIs32 : 1, /* TRUE if 32 bit driver, FALSE for 16 */ + bIsMapper : 1; /* TRUE if mapper */ + WINE_MM_DRIVER_PART parts[MMDRV_MAX];/* Information for all known types */ +} WINE_MM_DRIVER, *LPWINE_MM_DRIVER; + +typedef struct tagWINE_MLD { +/* EPP struct tagWINE_MLD* lpNext; */ /* not used so far */ + UINT uDeviceID; + UINT type; + UINT mmdIndex; /* index to low-level driver in MMDrvs table */ + DWORD dwDriverInstance; /* this value is driver related, as opposed to + * opendesc.dwInstance which is client (callback) related */ + WORD bFrom32; + WORD dwFlags; + DWORD dwCallback; + DWORD dwClientInstance; +} WINE_MLD, *LPWINE_MLD; + +typedef struct { + WINE_MLD mld; +} WINE_WAVE, *LPWINE_WAVE; + +typedef struct { + WINE_MLD mld; + MIDIOPENDESC mod; /* FIXME: should be removed */ +} WINE_MIDI, *LPWINE_MIDI; + +typedef struct { + WINE_MLD mld; +} WINE_MIXER, *LPWINE_MIXER; + +#define WINE_MMTHREAD_CREATED 0x4153494C /* "BSIL" */ +#define WINE_MMTHREAD_DELETED 0xDEADDEAD + +typedef struct { + DWORD dwSignature; /* 00 "BSIL" when ok, 0xDEADDEAD when being deleted */ + DWORD dwCounter; /* 04 > 1 when in mmThread functions */ + HANDLE hThread; /* 08 hThread */ + DWORD dwThreadID; /* 0C */ + FARPROC16 fpThread; /* 10 address of thread proc (segptr or lin depending on dwFlags) */ + DWORD dwThreadPmt; /* 14 parameter to be passed upon thread creation to fpThread */ + DWORD dwSignalCount; /* 18 counter used for signaling */ + HANDLE hEvent; /* 1C event */ + HANDLE hVxD; /* 20 return from OpenVxDHandle */ + DWORD dwStatus; /* 24 0x00, 0x10, 0x20, 0x30 */ + DWORD dwFlags; /* 28 dwFlags upon creation */ + HANDLE16 hTask; /* 2C handle to created task */ +} WINE_MMTHREAD; + +typedef struct tagWINE_MCIDRIVER { + UINT wDeviceID; + UINT wType; + LPSTR lpstrElementName; + LPSTR lpstrDeviceType; + LPSTR lpstrAlias; + HDRVR hDriver; + DRIVERPROC16 driverProc; + DWORD dwPrivate; + YIELDPROC lpfnYieldProc; + DWORD dwYieldData; + BOOL bIs32; + DWORD CreatorThread; + UINT uTypeCmdTable; + UINT uSpecificCmdTable; + struct tagWINE_MCIDRIVER*lpNext; +} WINE_MCIDRIVER, *LPWINE_MCIDRIVER; + +#define WINE_TIMER_IS32 0x80 + +typedef struct tagWINE_TIMERENTRY { + UINT wDelay; + UINT wResol; + FARPROC16 lpFunc; + DWORD dwUser; + UINT16 wFlags; + UINT16 wTimerID; + UINT uCurTime; + struct tagWINE_TIMERENTRY* lpNext; +} WINE_TIMERENTRY, *LPWINE_TIMERENTRY; + +enum mmioProcType {MMIO_PROC_16,MMIO_PROC_32A,MMIO_PROC_32W}; + +struct IOProcList +{ + struct IOProcList*pNext; /* Next item in linked list */ + FOURCC fourCC; /* four-character code identifying IOProc */ + LPMMIOPROC pIOProc; /* pointer to IProc */ + enum mmioProcType type; /* 16, 32A or 32W */ + int count; /* number of objects linked to it */ +}; + +typedef struct tagWINE_MMIO { + MMIOINFO info; + struct tagWINE_MMIO* lpNext; + struct IOProcList* ioProc; + BOOL bTmpIOProc : 1, + bBufferLoaded : 1; + SEGPTR segBuffer16; + DWORD dwFileSize; +} WINE_MMIO, *LPWINE_MMIO; + +typedef struct tagWINE_PLAYSOUND { + BOOL bLoop : 1, + bAlloc : 1; + LPCWSTR pszSound; + HMODULE hMod; + DWORD fdwSound; + struct tagWINE_PLAYSOUND* lpNext; +} WINE_PLAYSOUND, *LPWINE_PLAYSOUND; + +typedef struct tagWINE_MM_IDATA { + /* winmm part */ + HANDLE hWinMM32Instance; + HANDLE hWinMM16Instance; + CRITICAL_SECTION cs; + /* mm timer part */ + HANDLE hMMTimer; + DWORD mmSysTimeMS; + LPWINE_TIMERENTRY lpTimerList; + int nSizeLpTimers; + LPWINE_TIMERENTRY lpTimers; + /* mci part */ + LPWINE_MCIDRIVER lpMciDrvs; + /* low level drivers (unused yet) */ + /* LPWINE_WAVE lpWave; */ + /* LPWINE_MIDI lpMidi; */ + /* LPWINE_MIXER lpMixer; */ + /* mmio part */ + LPWINE_MMIO lpMMIO; + /* playsound and sndPlaySound */ + WINE_PLAYSOUND* lpPlaySound; + HANDLE psLastEvent; + HANDLE psStopEvent; +} WINE_MM_IDATA, *LPWINE_MM_IDATA; + +/* function prototypes */ + +typedef LONG (*MCIPROC16)(DWORD, HDRVR16, WORD, DWORD, DWORD); +typedef LONG (*MCIPROC)(DWORD, HDRVR, DWORD, DWORD, DWORD); +typedef WINMM_MapType (*MMDRV_MAPFUNC)(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2); +typedef WINMM_MapType (*MMDRV_UNMAPFUNC)(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT ret); + +LPWINE_DRIVER DRIVER_FindFromHDrvr(HDRVR hDrvr); +BOOL DRIVER_GetLibName(LPCSTR keyName, LPCSTR sectName, LPSTR buf, int sz); +LPWINE_DRIVER DRIVER_TryOpenDriver32(LPCSTR fn, LPARAM lParam2); +void DRIVER_UnloadAll(void); + +BOOL MMDRV_Init(void); +void MMDRV_Exit(void); +UINT MMDRV_GetNum(UINT); +LPWINE_MLD MMDRV_Alloc(UINT size, UINT type, LPHANDLE hndl, DWORD* dwFlags, + DWORD* dwCallback, DWORD* dwInstance, BOOL bFrom32); +void MMDRV_Free(HANDLE hndl, LPWINE_MLD mld); +DWORD MMDRV_Open(LPWINE_MLD mld, UINT wMsg, DWORD dwParam1, DWORD dwParam2); +DWORD MMDRV_Close(LPWINE_MLD mld, UINT wMsg); +LPWINE_MLD MMDRV_Get(HANDLE hndl, UINT type, BOOL bCanBeID); +LPWINE_MLD MMDRV_GetRelated(HANDLE hndl, UINT srcType, BOOL bSrcCanBeID, UINT dstTyped); +DWORD MMDRV_Message(LPWINE_MLD mld, WORD wMsg, DWORD dwParam1, DWORD dwParam2, BOOL bFrom32); +UINT MMDRV_PhysicalFeatures(LPWINE_MLD mld, UINT uMsg, DWORD dwParam1, DWORD dwParam2); +BOOL MMDRV_Is32(unsigned int); +void MMDRV_InstallMap(unsigned int, MMDRV_MAPFUNC, MMDRV_UNMAPFUNC, + MMDRV_MAPFUNC, MMDRV_UNMAPFUNC, LPDRVCALLBACK); + +BOOL MCI_Init(void); +WINE_MCIDRIVER* MCI_GetDriver(UINT16 uDevID); +UINT MCI_GetDriverFromString(LPCSTR str); +DWORD MCI_WriteString(LPSTR lpDstStr, DWORD dstSize, LPCSTR lpSrcStr); +const char* MCI_MessageToString(UINT16 wMsg); +UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data); +LRESULT MCI_CleanUp(LRESULT dwRet, UINT wMsg, DWORD dwParam2); +DWORD MCI_SendCommand(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2, BOOL bFrom32); +DWORD MCI_SendCommandFrom32(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2); +DWORD MCI_SendCommandFrom16(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2); +UINT MCI_SetCommandTable(void *table, UINT uDevType); + +BOOL WINMM_CheckForMMSystem(void); + +UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback, + DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32); +UINT MIDI_OutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback, + DWORD dwInstance, DWORD dwFlags, BOOL bFrom32); +UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback, + DWORD dwInstance, DWORD dwFlags, BOOL bFrom32); +MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, + DWORD cMidi, DWORD dwCallback, + DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32); +UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType, + LPCWAVEFORMATEX lpFormat, DWORD dwCallback, + DWORD dwInstance, DWORD dwFlags, BOOL bFrom32); + +HMMIO MMIO_Open(LPSTR szFileName, MMIOINFO* refmminfo, + DWORD dwOpenFlags, enum mmioProcType type); +LPMMIOPROC MMIO_InstallIOProc(FOURCC fccIOProc, LPMMIOPROC pIOProc, + DWORD dwFlags, enum mmioProcType type); +LRESULT MMIO_SendMessage(HMMIO hmmio, UINT uMessage, LPARAM lParam1, + LPARAM lParam2, enum mmioProcType type); +LPWINE_MMIO MMIO_Get(HMMIO h); + +WORD TIME_SetEventInternal(UINT wDelay, UINT wResol, + FARPROC16 lpFunc, DWORD dwUser, UINT wFlags); +void TIME_MMTimeStart(void); +void TIME_MMTimeStop(void); + +/* Global variables */ +extern LPWINE_MM_IDATA WINMM_IData; + +/* pointers to 16 bit functions (if sibling MMSYSTEM.DLL is loaded + * NULL otherwise + */ +extern WINE_MMTHREAD* (*pFnGetMMThread16)(HANDLE16); +extern LPWINE_DRIVER (*pFnOpenDriver16)(LPCSTR,LPCSTR,LPARAM); +extern LRESULT (*pFnCloseDriver16)(HDRVR16,LPARAM,LPARAM); +extern LRESULT (*pFnSendMessage16)(HDRVR16,UINT,LPARAM,LPARAM); +extern WINMM_MapType (*pFnMciMapMsg16To32A)(WORD,WORD,DWORD*); +extern WINMM_MapType (*pFnMciUnMapMsg16To32A)(WORD,WORD,DWORD); +extern WINMM_MapType (*pFnMciMapMsg32ATo16)(WORD,WORD,DWORD,DWORD*); +extern WINMM_MapType (*pFnMciUnMapMsg32ATo16)(WORD,WORD,DWORD,DWORD); +extern LRESULT (*pFnCallMMDrvFunc16)(FARPROC16,WORD,WORD,LONG,LONG,LONG); +extern unsigned (*pFnLoadMMDrvFunc16)(LPCSTR,LPWINE_DRIVER, LPWINE_MM_DRIVER); +extern LRESULT (*pFnMmioCallback16)(SEGPTR,LPMMIOINFO,UINT,LPARAM,LPARAM); + +/* mmsystem (16 bit files) only functions */ +void MMDRV_Init16(void); +void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16); +void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32); + +/* HANDLE16 -> HANDLE conversions */ +#define HDRVR_32(h16) ((HDRVR)(ULONG_PTR)(h16)) +#define HMIDI_32(h16) ((HMIDI)(ULONG_PTR)(h16)) +#define HMIDIIN_32(h16) ((HMIDIIN)(ULONG_PTR)(h16)) +#define HMIDIOUT_32(h16) ((HMIDIOUT)(ULONG_PTR)(h16)) +#define HMIDISTRM_32(h16) ((HMIDISTRM)(ULONG_PTR)(h16)) +#define HMIXER_32(h16) ((HMIXER)(ULONG_PTR)(h16)) +#define HMIXEROBJ_32(h16) ((HMIXEROBJ)(ULONG_PTR)(h16)) +#define HMMIO_32(h16) ((HMMIO)(ULONG_PTR)(h16)) +#define HWAVE_32(h16) ((HWAVE)(ULONG_PTR)(h16)) +#define HWAVEIN_32(h16) ((HWAVEIN)(ULONG_PTR)(h16)) +#define HWAVEOUT_32(h16) ((HWAVEOUT)(ULONG_PTR)(h16)) + +/* HANDLE -> HANDLE16 conversions */ +#define HDRVR_16(h32) (LOWORD(h32)) +#define HMIDI_16(h32) (LOWORD(h32)) +#define HMIDIIN_16(h32) (LOWORD(h32)) +#define HMIDIOUT_16(h32) (LOWORD(h32)) +#define HMIDISTRM_16(h32) (LOWORD(h32)) +#define HMIXER_16(h32) (LOWORD(h32)) +#define HMIXEROBJ_16(h32) (LOWORD(h32)) +#define HMMIO_16(h32) (LOWORD(h32)) +#define HWAVE_16(h32) (LOWORD(h32)) +#define HWAVEIN_16(h32) (LOWORD(h32)) +#define HWAVEOUT_16(h32) (LOWORD(h32)) diff --git a/reactos/lib/winmm/winmm.c b/reactos/lib/winmm/winmm.c new file mode 100644 index 00000000000..218809524ed --- /dev/null +++ b/reactos/lib/winmm/winmm.c @@ -0,0 +1,2881 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/* + * WINMM functions + * + * Copyright 1993 Martin Ayotte + * 1998-2002 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Eric POUECH : + * 98/9 added Win32 MCI support + * 99/4 added midiStream support + * 99/9 added support for loadable low level drivers + */ + +// AG: This didn't work with w32api, so I've fixed it: +//#define NONAMELESSUNION +//#define NONAMELESSSTRUCT + +#ifdef __WINE_FOR_REACTOS__ + +#include +typedef UINT *LPUINT; +#include +#include "internal.h" + +#else + +#include "winbase.h" +#include "winuser.h" +#include "heap.h" +#include "winternl.h" +#include "wine/debug.h" +WINE_DEFAULT_DEBUG_CHANNEL(winmm); + +#endif + +#include +#include "winemm.h" + + +#ifdef __WINE_FOR_REACTOS__ +typedef MIDIEVENT *LPMIDIEVENT; +#endif + + +/****************************************************************** + * MyUserYield + * + * Internal wrapper to call USER.UserYield16 (in fact through a Wine only export from USER32). + */ +static void MyUserYield(void) +{ + HMODULE mod = GetModuleHandleA( "user32.dll" ); + if (mod) + { + FARPROC proc = GetProcAddress( mod, "UserYield16" ); + if (proc) proc(); + } +} + +/* ======================================================================== + * G L O B A L S E T T I N G S + * ========================================================================*/ + +LPWINE_MM_IDATA WINMM_IData /* = NULL */; + +/************************************************************************** + * WINMM_CreateIData [internal] + */ +static BOOL WINMM_CreateIData(HINSTANCE hInstDLL) +{ + WINMM_IData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MM_IDATA)); + + if (!WINMM_IData) + return FALSE; + WINMM_IData->hWinMM32Instance = hInstDLL; + InitializeCriticalSection(&WINMM_IData->cs); + WINMM_IData->cs.DebugInfo = (void*)__FILE__ ": WinMM"; + WINMM_IData->psStopEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + WINMM_IData->psLastEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + TRACE("Created IData (%p)\n", WINMM_IData); + return TRUE; +} + +/************************************************************************** + * WINMM_DeleteIData [internal] + */ +static void WINMM_DeleteIData(void) +{ + if (WINMM_IData) { + TIME_MMTimeStop(); + + /* FIXME: should also free content and resources allocated + * inside WINMM_IData */ + CloseHandle(WINMM_IData->psStopEvent); + CloseHandle(WINMM_IData->psLastEvent); + DeleteCriticalSection(&WINMM_IData->cs); + HeapFree(GetProcessHeap(), 0, WINMM_IData); + WINMM_IData = NULL; + } +} + +/****************************************************************** + * WINMM_LoadMMSystem + * + */ +static HANDLE (WINAPI *pGetModuleHandle16)(LPCSTR); +static DWORD (WINAPI *pLoadLibrary16)(LPCSTR); + +BOOL WINMM_CheckForMMSystem(void) +{ + /* 0 is not checked yet, -1 is not present, 1 is present */ + static int loaded /* = 0 */; + + if (loaded == 0) + { + HANDLE h = GetModuleHandleA("kernel32"); + loaded = -1; + if (h) + { + pGetModuleHandle16 = (void*)GetProcAddress(h, "GetModuleHandle16"); + pLoadLibrary16 = (void*)GetProcAddress(h, "LoadLibrary16"); + if (pGetModuleHandle16 && pLoadLibrary16 && + (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL"))) + loaded = 1; + } + } + return loaded > 0; +} + +/************************************************************************** + * DllMain (WINMM.init) + * + * WINMM DLL entry point + * + */ +BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad) +{ + TRACE("%p 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad); + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hInstDLL); + + if (!WINMM_CreateIData(hInstDLL)) + return FALSE; + if (!MCI_Init() || !MMDRV_Init()) { + WINMM_DeleteIData(); + return FALSE; + } + break; + case DLL_PROCESS_DETACH: + /* close all opened MCI drivers */ + MCI_SendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0L, TRUE); + MMDRV_Exit(); + /* now unload all remaining drivers... */ + DRIVER_UnloadAll(); + + WINMM_DeleteIData(); + break; + } + return TRUE; +} + +/************************************************************************** + * Mixer devices. New to Win95 + */ + +/************************************************************************** + * find out the real mixer ID depending on hmix (depends on dwFlags) + */ +static LPWINE_MIXER MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags) +{ + LPWINE_MIXER lpwm = NULL; + + switch (dwFlags & 0xF0000000ul) { + case MIXER_OBJECTF_MIXER: + lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE); + break; + case MIXER_OBJECTF_HMIXER: + lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE); + break; + case MIXER_OBJECTF_WAVEOUT: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_HWAVEOUT: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_WAVEIN: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_HWAVEIN: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_MIDIOUT: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_HMIDIOUT: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_MIDIIN: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_HMIDIIN: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_AUX: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER); + break; + default: + FIXME("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul); + break; + } + return lpwm; +} + +/************************************************************************** + * mixerGetNumDevs [WINMM.@] + */ +UINT WINAPI mixerGetNumDevs(void) +{ + return MMDRV_GetNum(MMDRV_MIXER); +} + +/************************************************************************** + * mixerGetDevCapsA [WINMM.@] + */ +UINT WINAPI mixerGetDevCapsA(UINT devid, LPMIXERCAPSA mixcaps, UINT size) +{ + LPWINE_MLD wmld; + + if ((wmld = MMDRV_Get((HANDLE)devid, MMDRV_MIXER, TRUE)) == NULL) + return MMSYSERR_BADDEVICEID; + + return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD)mixcaps, size, TRUE); +} + +/************************************************************************** + * mixerGetDevCapsW [WINMM.@] + */ +UINT WINAPI mixerGetDevCapsW(UINT devid, LPMIXERCAPSW mixcaps, UINT size) +{ + MIXERCAPSA micA; + UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA)); + + if (ret == MMSYSERR_NOERROR) { + mixcaps->wMid = micA.wMid; + mixcaps->wPid = micA.wPid; + mixcaps->vDriverVersion = micA.vDriverVersion; + MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, mixcaps->szPname, + sizeof(mixcaps->szPname)/sizeof(WCHAR) ); + mixcaps->fdwSupport = micA.fdwSupport; + mixcaps->cDestinations = micA.cDestinations; + } + return ret; +} + +UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback, + DWORD dwInstance, DWORD fdwOpen, BOOL bFrom32) +{ + HANDLE hMix; + LPWINE_MLD wmld; + DWORD dwRet = 0; + MIXEROPENDESC mod; + + TRACE("(%p, %d, %08lx, %08lx, %08lx)\n", + lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen); + + wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen, + &dwCallback, &dwInstance, bFrom32); + + wmld->uDeviceID = uDeviceID; + mod.hmx = (HMIXEROBJ)hMix; + mod.dwCallback = dwCallback; + mod.dwInstance = dwInstance; + + dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen); + + if (dwRet != MMSYSERR_NOERROR) { + MMDRV_Free(hMix, wmld); + hMix = 0; + } + if (lphMix) *lphMix = hMix; + TRACE("=> %ld hMixer=%p\n", dwRet, hMix); + + return dwRet; +} + +/************************************************************************** + * mixerOpen [WINMM.@] + */ +UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD dwCallback, + DWORD dwInstance, DWORD fdwOpen) +{ + return MIXER_Open(lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen, TRUE); +} + +/************************************************************************** + * mixerClose [WINMM.@] + */ +UINT WINAPI mixerClose(HMIXER hMix) +{ + LPWINE_MLD wmld; + DWORD dwRet; + + TRACE("(%p)\n", hMix); + + if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE; + + dwRet = MMDRV_Close(wmld, MXDM_CLOSE); + MMDRV_Free(hMix, wmld); + + return dwRet; +} + +/************************************************************************** + * mixerGetID [WINMM.@] + */ +UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID) +{ + LPWINE_MIXER lpwm; + + TRACE("(%p %p %08lx)\n", hmix, lpid, fdwID); + + if ((lpwm = MIXER_GetDev(hmix, fdwID)) == NULL) { + return MMSYSERR_INVALHANDLE; + } + + if (lpid) + *lpid = lpwm->mld.uDeviceID; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mixerGetControlDetailsA [WINMM.@] + */ +UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA, + DWORD fdwDetails) +{ + LPWINE_MIXER lpwm; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails); + + if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL) + return MMSYSERR_INVALHANDLE; + + if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA)) + return MMSYSERR_INVALPARAM; + + return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD)lpmcdA, + fdwDetails, TRUE); +} + +/************************************************************************** + * mixerGetControlDetailsW [WINMM.@] + */ +UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails) +{ + DWORD ret = MMSYSERR_NOTENABLED; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmcd, fdwDetails); + + if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd)) + return MMSYSERR_INVALPARAM; + + switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) { + case MIXER_GETCONTROLDETAILSF_VALUE: + /* can savely use W structure as it is, no string inside */ + ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails); + break; + case MIXER_GETCONTROLDETAILSF_LISTTEXT: + { + MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails; + MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA; + int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA); + int i; + + if (lpmcd->cMultipleItems != 0) { + size *= lpmcd->cMultipleItems; + } + pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size); + lpmcd->paDetails = pDetailsA; + lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA); + /* set up lpmcd->paDetails */ + ret = mixerGetControlDetailsA(hmix, lpmcd, fdwDetails); + /* copy from lpmcd->paDetails back to paDetailsW; */ + if(ret == MMSYSERR_NOERROR) { + for(i=0;icMultipleItems*lpmcd->cChannels;i++) { + pDetailsW->dwParam1 = pDetailsA->dwParam1; + pDetailsW->dwParam2 = pDetailsA->dwParam2; + MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1, + pDetailsW->szName, + sizeof(pDetailsW->szName)/sizeof(WCHAR) ); + pDetailsA++; + pDetailsW++; + } + pDetailsA -= lpmcd->cMultipleItems*lpmcd->cChannels; + pDetailsW -= lpmcd->cMultipleItems*lpmcd->cChannels; + } + HeapFree(GetProcessHeap(), 0, pDetailsA); + lpmcd->paDetails = pDetailsW; + lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW); + } + break; + default: + ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails); + } + + return ret; +} + +/************************************************************************** + * mixerGetLineControlsA [WINMM.@] + */ +UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA, + DWORD fdwControls) +{ + LPWINE_MIXER lpwm; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmlcA, fdwControls); + + if ((lpwm = MIXER_GetDev(hmix, fdwControls)) == NULL) + return MMSYSERR_INVALHANDLE; + + if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA)) + return MMSYSERR_INVALPARAM; + + return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD)lpmlcA, + fdwControls, TRUE); +} + +/************************************************************************** + * mixerGetLineControlsW [WINMM.@] + */ +UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW, + DWORD fdwControls) +{ + MIXERLINECONTROLSA mlcA; + DWORD ret; + int i; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmlcW, fdwControls); + + if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) || + lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW)) + return MMSYSERR_INVALPARAM; + + mlcA.cbStruct = sizeof(mlcA); + mlcA.dwLineID = lpmlcW->dwLineID; + mlcA.dwControlID = lpmlcW->dwControlID; + mlcA.dwControlType = lpmlcW->dwControlType; + mlcA.cControls = lpmlcW->cControls; + mlcA.cbmxctrl = sizeof(MIXERCONTROLA); + mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0, + mlcA.cControls * mlcA.cbmxctrl); + + ret = mixerGetLineControlsA(hmix, &mlcA, fdwControls); + + if (ret == MMSYSERR_NOERROR) { + lpmlcW->dwLineID = mlcA.dwLineID; + lpmlcW->dwControlID = mlcA.dwControlID; + lpmlcW->dwControlType = mlcA.dwControlType; + lpmlcW->cControls = mlcA.cControls; + + for (i = 0; i < mlcA.cControls; i++) { + lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW); + lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID; + lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType; + lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl; + lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems; + MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1, + lpmlcW->pamxctrl[i].szShortName, + sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1, + lpmlcW->pamxctrl[i].szName, + sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) ); + /* sizeof(lpmlcW->pamxctrl[i].Bounds) == + * sizeof(mlcA.pamxctrl[i].Bounds) */ + memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds, + sizeof(mlcA.pamxctrl[i].Bounds)); + /* sizeof(lpmlcW->pamxctrl[i].Metrics) == + * sizeof(mlcA.pamxctrl[i].Metrics) */ + memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics, + sizeof(mlcA.pamxctrl[i].Metrics)); + } + } + + HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl); + + return ret; +} + +/************************************************************************** + * mixerGetLineInfoA [WINMM.@] + */ +UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliW, DWORD fdwInfo) +{ + LPWINE_MIXER lpwm; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo); + + if ((lpwm = MIXER_GetDev(hmix, fdwInfo)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD)lpmliW, + fdwInfo, TRUE); +} + +/************************************************************************** + * mixerGetLineInfoW [WINMM.@] + */ +UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW, + DWORD fdwInfo) +{ + MIXERLINEA mliA; + UINT ret; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo); + + if (lpmliW == NULL || lpmliW->cbStruct != sizeof(*lpmliW)) + return MMSYSERR_INVALPARAM; + + mliA.cbStruct = sizeof(mliA); + switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) { + case MIXER_GETLINEINFOF_COMPONENTTYPE: + mliA.dwComponentType = lpmliW->dwComponentType; + break; + case MIXER_GETLINEINFOF_DESTINATION: + mliA.dwDestination = lpmliW->dwDestination; + break; + case MIXER_GETLINEINFOF_LINEID: + mliA.dwLineID = lpmliW->dwLineID; + break; + case MIXER_GETLINEINFOF_SOURCE: + mliA.dwDestination = lpmliW->dwDestination; + mliA.dwSource = lpmliW->dwSource; + break; + case MIXER_GETLINEINFOF_TARGETTYPE: + mliA.Target.dwType = lpmliW->Target.dwType; + mliA.Target.wMid = lpmliW->Target.wMid; + mliA.Target.wPid = lpmliW->Target.wPid; + mliA.Target.vDriverVersion = lpmliW->Target.vDriverVersion; + WideCharToMultiByte( CP_ACP, 0, lpmliW->Target.szPname, -1, mliA.Target.szPname, sizeof(mliA.Target.szPname), NULL, NULL); + break; + default: + FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo); + } + + ret = mixerGetLineInfoA(hmix, &mliA, fdwInfo); + + lpmliW->dwDestination = mliA.dwDestination; + lpmliW->dwSource = mliA.dwSource; + lpmliW->dwLineID = mliA.dwLineID; + lpmliW->fdwLine = mliA.fdwLine; + lpmliW->dwUser = mliA.dwUser; + lpmliW->dwComponentType = mliA.dwComponentType; + lpmliW->cChannels = mliA.cChannels; + lpmliW->cConnections = mliA.cConnections; + lpmliW->cControls = mliA.cControls; + MultiByteToWideChar( CP_ACP, 0, mliA.szShortName, -1, lpmliW->szShortName, + sizeof(lpmliW->szShortName)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, mliA.szName, -1, lpmliW->szName, + sizeof(lpmliW->szName)/sizeof(WCHAR) ); + lpmliW->Target.dwType = mliA.Target.dwType; + lpmliW->Target.dwDeviceID = mliA.Target.dwDeviceID; + lpmliW->Target.wMid = mliA.Target.wMid; + lpmliW->Target.wPid = mliA.Target.wPid; + lpmliW->Target.vDriverVersion = mliA.Target.vDriverVersion; + MultiByteToWideChar( CP_ACP, 0, mliA.Target.szPname, -1, lpmliW->Target.szPname, + sizeof(lpmliW->Target.szPname)/sizeof(WCHAR) ); + + return ret; +} + +/************************************************************************** + * mixerSetControlDetails [WINMM.@] + */ +UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA, + DWORD fdwDetails) +{ + LPWINE_MIXER lpwm; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails); + + if ((lpwm = MIXER_GetDev(hmix, fdwDetails)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD)lpmcdA, + fdwDetails, TRUE); +} + +/************************************************************************** + * mixerMessage [WINMM.@] + */ +DWORD WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n", + (DWORD)hmix, uMsg, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE); +} + +/************************************************************************** + * auxGetNumDevs [WINMM.@] + */ +UINT WINAPI auxGetNumDevs(void) +{ + return MMDRV_GetNum(MMDRV_AUX); +} + +/************************************************************************** + * auxGetDevCapsW [WINMM.@] + */ +UINT WINAPI auxGetDevCapsW(UINT uDeviceID, LPAUXCAPSW lpCaps, UINT uSize) +{ + AUXCAPSA acA; + UINT ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA)); + + lpCaps->wMid = acA.wMid; + lpCaps->wPid = acA.wPid; + lpCaps->vDriverVersion = acA.vDriverVersion; + MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, lpCaps->szPname, + sizeof(lpCaps->szPname)/sizeof(WCHAR) ); + lpCaps->wTechnology = acA.wTechnology; + lpCaps->dwSupport = acA.dwSupport; + return ret; +} + +/************************************************************************** + * auxGetDevCapsA [WINMM.@] + */ +UINT WINAPI auxGetDevCapsA(UINT uDeviceID, LPAUXCAPSA lpCaps, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize); + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE); +} + +/************************************************************************** + * auxGetVolume [WINMM.@] + */ +UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume); + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE); +} + +/************************************************************************** + * auxSetVolume [WINMM.@] + */ +UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume); + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE); +} + +/************************************************************************** + * auxOutMessage [WINMM.@] + */ +DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2) +{ + LPWINE_MLD wmld; + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE); +} + +/************************************************************************** + * mciGetErrorStringW [WINMM.@] + */ +BOOL WINAPI mciGetErrorStringW(DWORD wError, LPWSTR lpstrBuffer, UINT uLength) +{ + LPSTR bufstr = HeapAlloc(GetProcessHeap(), 0, uLength); + BOOL ret = mciGetErrorStringA(wError, bufstr, uLength); + + MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength ); + HeapFree(GetProcessHeap(), 0, bufstr); + return ret; +} + +/************************************************************************** + * mciGetErrorStringA [WINMM.@] + */ +BOOL WINAPI mciGetErrorStringA(DWORD dwError, LPSTR lpstrBuffer, UINT uLength) +{ + BOOL16 ret = FALSE; + + if (lpstrBuffer != NULL && uLength > 0 && + dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) { + + if (LoadStringA(WINMM_IData->hWinMM32Instance, + dwError, lpstrBuffer, uLength) > 0) { + ret = TRUE; + } + } + return ret; +} + +/************************************************************************** + * mciDriverNotify [WINMM.@] + */ +BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus) +{ + + TRACE("(%p, %04x, %04X)\n", hWndCallBack, wDevID, wStatus); + + return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID); +} + +/************************************************************************** + * mciGetDriverData [WINMM.@] + */ +DWORD WINAPI mciGetDriverData(UINT uDeviceID) +{ + LPWINE_MCIDRIVER wmd; + + TRACE("(%04x)\n", uDeviceID); + + wmd = MCI_GetDriver(uDeviceID); + + if (!wmd) { + WARN("Bad uDeviceID\n"); + return 0L; + } + + return wmd->dwPrivate; +} + +/************************************************************************** + * mciSetDriverData [WINMM.@] + */ +BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD data) +{ + LPWINE_MCIDRIVER wmd; + + TRACE("(%04x, %08lx)\n", uDeviceID, data); + + wmd = MCI_GetDriver(uDeviceID); + + if (!wmd) { + WARN("Bad uDeviceID\n"); + return FALSE; + } + + wmd->dwPrivate = data; + return TRUE; +} + +/************************************************************************** + * mciSendCommandA [WINMM.@] + */ +DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2) +{ + DWORD dwRet; + + TRACE("(%08x, %s, %08lx, %08lx)\n", + wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2); + + dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE); + dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2); + TRACE("=> %08lx\n", dwRet); + return dwRet; +} + +/************************************************************************** + * mciSendCommandW [WINMM.@] + */ +DWORD WINAPI mciSendCommandW(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2) +{ + FIXME("(%08x, %s, %08lx, %08lx): stub\n", + wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2); + return MCIERR_UNSUPPORTED_FUNCTION; +} + +/************************************************************************** + * mciGetDeviceIDA [WINMM.@] + */ +UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName) +{ + return MCI_GetDriverFromString(lpstrName); +} + +/************************************************************************** + * mciGetDeviceIDW [WINMM.@] + */ +UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName) +{ + LPSTR lpstrName; + UINT ret; + + lpstrName = (LPSTR) HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrName); + ret = MCI_GetDriverFromString(lpstrName); + HeapFree(GetProcessHeap(), 0, lpstrName); + return ret; +} + +/************************************************************************** + * MCI_DefYieldProc [internal] + */ +UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data) +{ + INT16 ret; + + TRACE("(0x%04x, 0x%08lx)\n", wDevID, data); + + if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) || + (GetAsyncKeyState(LOWORD(data)) & 1) == 0) { + MyUserYield(); + ret = 0; + } else { + MSG msg; + + msg.hwnd = (HWND) HWND_32(HIWORD(data)); + while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); + ret = -1; + } + return ret; +} + +/************************************************************************** + * mciSetYieldProc [WINMM.@] + */ +BOOL WINAPI mciSetYieldProc(UINT uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData) +{ + LPWINE_MCIDRIVER wmd; + + TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData); + + if (!(wmd = MCI_GetDriver(uDeviceID))) { + WARN("Bad uDeviceID\n"); + return FALSE; + } + + wmd->lpfnYieldProc = fpYieldProc; + wmd->dwYieldData = dwYieldData; + wmd->bIs32 = TRUE; + + return TRUE; +} + +/************************************************************************** + * mciGetDeviceIDFromElementIDW [WINMM.@] + */ +UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType) +{ + /* FIXME: that's rather strange, there is no + * mciGetDeviceIDFromElementID32A in winmm.spec + */ + FIXME("(%lu, %p) stub\n", dwElementID, lpstrType); + return 0; +} + +/************************************************************************** + * mciGetYieldProc [WINMM.@] + */ +YIELDPROC WINAPI mciGetYieldProc(UINT uDeviceID, DWORD* lpdwYieldData) +{ + LPWINE_MCIDRIVER wmd; + + TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData); + + if (!(wmd = MCI_GetDriver(uDeviceID))) { + WARN("Bad uDeviceID\n"); + return NULL; + } + if (!wmd->lpfnYieldProc) { + WARN("No proc set\n"); + return NULL; + } + if (!wmd->bIs32) { + WARN("Proc is 32 bit\n"); + return NULL; + } + return wmd->lpfnYieldProc; +} + +/************************************************************************** + * mciGetCreatorTask [WINMM.@] + */ +HTASK WINAPI mciGetCreatorTask(UINT uDeviceID) +{ + LPWINE_MCIDRIVER wmd; + HTASK ret = 0; + + if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread; + + TRACE("(%u) => %p\n", uDeviceID, ret); + return ret; +} + +/************************************************************************** + * mciDriverYield [WINMM.@] + */ +UINT WINAPI mciDriverYield(UINT uDeviceID) +{ + LPWINE_MCIDRIVER wmd; + UINT ret = 0; + + TRACE("(%04x)\n", uDeviceID); + + if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) { + MyUserYield(); + } else { + ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData); + } + + return ret; +} + +/************************************************************************** + * midiOutGetNumDevs [WINMM.@] + */ +UINT WINAPI midiOutGetNumDevs(void) +{ + return MMDRV_GetNum(MMDRV_MIDIOUT); +} + +/************************************************************************** + * midiOutGetDevCapsW [WINMM.@] + */ +UINT WINAPI midiOutGetDevCapsW(UINT uDeviceID, LPMIDIOUTCAPSW lpCaps, + UINT uSize) +{ + MIDIOUTCAPSA mocA; + UINT ret; + + ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA)); + lpCaps->wMid = mocA.wMid; + lpCaps->wPid = mocA.wPid; + lpCaps->vDriverVersion = mocA.vDriverVersion; + MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, lpCaps->szPname, + sizeof(lpCaps->szPname)/sizeof(WCHAR) ); + lpCaps->wTechnology = mocA.wTechnology; + lpCaps->wVoices = mocA.wVoices; + lpCaps->wNotes = mocA.wNotes; + lpCaps->wChannelMask = mocA.wChannelMask; + lpCaps->dwSupport = mocA.dwSupport; + return ret; +} + +/************************************************************************** + * midiOutGetDevCapsA [WINMM.@] + */ +UINT WINAPI midiOutGetDevCapsA(UINT uDeviceID, LPMIDIOUTCAPSA lpCaps, + UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize); + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE); +} + +/************************************************************************** + * MIDI_GetErrorText [internal] + */ +static UINT16 MIDI_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize) +{ + UINT16 ret = MMSYSERR_BADERRNUM; + + if (lpText == NULL) { + ret = MMSYSERR_INVALPARAM; + } else if (uSize == 0) { + ret = MMSYSERR_NOERROR; + } else if ( + /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit + * a warning for the test was always true */ + (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) || + (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) { + + if (LoadStringA(WINMM_IData->hWinMM32Instance, + uError, lpText, uSize) > 0) { + ret = MMSYSERR_NOERROR; + } + } + return ret; +} + +/************************************************************************** + * midiOutGetErrorTextA [WINMM.@] + */ +UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize) +{ + return MIDI_GetErrorText(uError, lpText, uSize); +} + +/************************************************************************** + * midiOutGetErrorTextW [WINMM.@] + */ +UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize) +{ + LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize); + UINT ret; + + ret = MIDI_GetErrorText(uError, xstr, uSize); + MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize ); + HeapFree(GetProcessHeap(), 0, xstr); + return ret; +} + +/************************************************************************** + * MIDI_OutAlloc [internal] + */ +static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback, + LPDWORD lpdwInstance, LPDWORD lpdwFlags, + DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32) +{ + HANDLE hMidiOut; + LPWINE_MIDI lpwm; + UINT size; + + size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID); + + lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags, + lpdwCallback, lpdwInstance, bFrom32); + + if (lphMidiOut != NULL) + *lphMidiOut = hMidiOut; + + if (lpwm) { + lpwm->mod.hMidi = (HMIDI) hMidiOut; + lpwm->mod.dwCallback = *lpdwCallback; + lpwm->mod.dwInstance = *lpdwInstance; + lpwm->mod.dnDevNode = 0; + lpwm->mod.cIds = cIDs; + if (cIDs) + memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID)); + } + return lpwm; +} + +UINT MIDI_OutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD dwCallback, + DWORD dwInstance, DWORD dwFlags, BOOL bFrom32) +{ + HMIDIOUT hMidiOut; + LPWINE_MIDI lpwm; + UINT dwRet = 0; + + TRACE("(%p, %d, %08lX, %08lX, %08lX);\n", + lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags); + + if (lphMidiOut != NULL) *lphMidiOut = 0; + + lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags, + 0, NULL, bFrom32); + + if (lpwm == NULL) + return MMSYSERR_NOMEM; + + lpwm->mld.uDeviceID = uDeviceID; + + dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod, dwFlags); + + if (dwRet != MMSYSERR_NOERROR) { + MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm); + hMidiOut = 0; + } + + if (lphMidiOut) *lphMidiOut = hMidiOut; + TRACE("=> %d hMidi=%p\n", dwRet, hMidiOut); + + return dwRet; +} + +/************************************************************************** + * midiOutOpen [WINMM.@] + */ +UINT WINAPI midiOutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, + DWORD dwCallback, DWORD dwInstance, DWORD dwFlags) +{ + return MIDI_OutOpen(lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE); +} + +/************************************************************************** + * midiOutClose [WINMM.@] + */ +UINT WINAPI midiOutClose(HMIDIOUT hMidiOut) +{ + LPWINE_MLD wmld; + DWORD dwRet; + + TRACE("(%p)\n", hMidiOut); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + dwRet = MMDRV_Close(wmld, MODM_CLOSE); + MMDRV_Free(hMidiOut, wmld); + + return dwRet; +} + +/************************************************************************** + * midiOutPrepareHeader [WINMM.@] + */ +UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut, + MIDIHDR* lpMidiOutHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_PREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE); +} + +/************************************************************************** + * midiOutUnprepareHeader [WINMM.@] + */ +UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut, + MIDIHDR* lpMidiOutHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); + + if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD)lpMidiOutHdr, uSize, TRUE); +} + +/************************************************************************** + * midiOutShortMsg [WINMM.@] + */ +UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %08lX)\n", hMidiOut, dwMsg); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, TRUE); +} + +/************************************************************************** + * midiOutLongMsg [WINMM.@] + */ +UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut, + MIDIHDR* lpMidiOutHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD)lpMidiOutHdr, uSize, TRUE); +} + +/************************************************************************** + * midiOutReset [WINMM.@] + */ +UINT WINAPI midiOutReset(HMIDIOUT hMidiOut) +{ + LPWINE_MLD wmld; + + TRACE("(%p)\n", hMidiOut); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE); +} + +/************************************************************************** + * midiOutGetVolume [WINMM.@] + */ +UINT WINAPI midiOutGetVolume(HMIDIOUT hMidiOut, DWORD* lpdwVolume) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p);\n", hMidiOut, lpdwVolume); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD)lpdwVolume, 0L, TRUE); +} + +/************************************************************************** + * midiOutSetVolume [WINMM.@] + */ +UINT WINAPI midiOutSetVolume(HMIDIOUT hMidiOut, DWORD dwVolume) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %ld);\n", hMidiOut, dwVolume); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE); +} + +/************************************************************************** + * midiOutCachePatches [WINMM.@] + */ +UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank, + WORD* lpwPatchArray, UINT uFlags) +{ + /* not really necessary to support this */ + FIXME("not supported yet\n"); + return MMSYSERR_NOTSUPPORTED; +} + +/************************************************************************** + * midiOutCacheDrumPatches [WINMM.@] + */ +UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch, + WORD* lpwKeyArray, UINT uFlags) +{ + FIXME("not supported yet\n"); + return MMSYSERR_NOTSUPPORTED; +} + +/************************************************************************** + * midiOutGetID [WINMM.@] + */ +UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p)\n", hMidiOut, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * midiOutMessage [WINMM.@] + */ +DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage, + DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) { + /* HACK... */ + if (uMessage == 0x0001) { + *(LPDWORD)dwParam1 = 1; + return 0; + } + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) { + return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); + } + return MMSYSERR_INVALHANDLE; + } + + switch (uMessage) { + case MODM_OPEN: + case MODM_CLOSE: + FIXME("can't handle OPEN or CLOSE message!\n"); + return MMSYSERR_NOTSUPPORTED; + } + return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); +} + +/************************************************************************** + * midiInGetNumDevs [WINMM.@] + */ +UINT WINAPI midiInGetNumDevs(void) +{ + return MMDRV_GetNum(MMDRV_MIDIIN); +} + +/************************************************************************** + * midiInGetDevCapsW [WINMM.@] + */ +UINT WINAPI midiInGetDevCapsW(UINT uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize) +{ + MIDIINCAPSA micA; + UINT ret = midiInGetDevCapsA(uDeviceID, &micA, uSize); + + if (ret == MMSYSERR_NOERROR) { + lpCaps->wMid = micA.wMid; + lpCaps->wPid = micA.wPid; + lpCaps->vDriverVersion = micA.vDriverVersion; + MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, lpCaps->szPname, + sizeof(lpCaps->szPname)/sizeof(WCHAR) ); + lpCaps->dwSupport = micA.dwSupport; + } + return ret; +} + +/************************************************************************** + * midiInGetDevCapsA [WINMM.@] + */ +UINT WINAPI midiInGetDevCapsA(UINT uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize); + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE); +} + +/************************************************************************** + * midiInGetErrorTextW [WINMM.@] + */ +UINT WINAPI midiInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize) +{ + LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize); + UINT ret = MIDI_GetErrorText(uError, xstr, uSize); + + MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize ); + HeapFree(GetProcessHeap(), 0, xstr); + return ret; +} + +/************************************************************************** + * midiInGetErrorTextA [WINMM.@] + */ +UINT WINAPI midiInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize) +{ + return MIDI_GetErrorText(uError, lpText, uSize); +} + +UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD dwCallback, + DWORD dwInstance, DWORD dwFlags, BOOL bFrom32) +{ + HANDLE hMidiIn; + LPWINE_MIDI lpwm; + DWORD dwRet = 0; + + TRACE("(%p, %d, %08lX, %08lX, %08lX);\n", + lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags); + + if (lphMidiIn != NULL) *lphMidiIn = 0; + + lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn, + &dwFlags, &dwCallback, &dwInstance, bFrom32); + + if (lpwm == NULL) + return MMSYSERR_NOMEM; + + lpwm->mod.hMidi = (HMIDI) hMidiIn; + lpwm->mod.dwCallback = dwCallback; + lpwm->mod.dwInstance = dwInstance; + + lpwm->mld.uDeviceID = uDeviceID; + dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags); + + if (dwRet != MMSYSERR_NOERROR) { + MMDRV_Free(hMidiIn, &lpwm->mld); + hMidiIn = 0; + } + if (lphMidiIn != NULL) *lphMidiIn = hMidiIn; + TRACE("=> %ld hMidi=%p\n", dwRet, hMidiIn); + + return dwRet; +} + +/************************************************************************** + * midiInOpen [WINMM.@] + */ +UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, + DWORD dwCallback, DWORD dwInstance, DWORD dwFlags) +{ + return MIDI_InOpen(lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE); +} + +/************************************************************************** + * midiInClose [WINMM.@] + */ +UINT WINAPI midiInClose(HMIDIIN hMidiIn) +{ + LPWINE_MLD wmld; + DWORD dwRet; + + TRACE("(%p)\n", hMidiIn); + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + dwRet = MMDRV_Close(wmld, MIDM_CLOSE); + MMDRV_Free(hMidiIn, wmld); + return dwRet; +} + +/************************************************************************** + * midiInPrepareHeader [WINMM.@] + */ +UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn, + MIDIHDR* lpMidiInHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD)lpMidiInHdr, uSize, TRUE); +} + +/************************************************************************** + * midiInUnprepareHeader [WINMM.@] + */ +UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn, + MIDIHDR* lpMidiInHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); + + if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD)lpMidiInHdr, uSize, TRUE); +} + +/************************************************************************** + * midiInAddBuffer [WINMM.@] + */ +UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn, + MIDIHDR* lpMidiInHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD)lpMidiInHdr, uSize, TRUE); +} + +/************************************************************************** + * midiInStart [WINMM.@] + */ +UINT WINAPI midiInStart(HMIDIIN hMidiIn) +{ + LPWINE_MLD wmld; + + TRACE("(%p)\n", hMidiIn); + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE); +} + +/************************************************************************** + * midiInStop [WINMM.@] + */ +UINT WINAPI midiInStop(HMIDIIN hMidiIn) +{ + LPWINE_MLD wmld; + + TRACE("(%p)\n", hMidiIn); + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE); +} + +/************************************************************************** + * midiInReset [WINMM.@] + */ +UINT WINAPI midiInReset(HMIDIIN hMidiIn) +{ + LPWINE_MLD wmld; + + TRACE("(%p)\n", hMidiIn); + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE); +} + +/************************************************************************** + * midiInGetID [WINMM.@] + */ +UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p)\n", hMidiIn, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * midiInMessage [WINMM.@] + */ +DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage, + DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + switch (uMessage) { + case MIDM_OPEN: + case MIDM_CLOSE: + FIXME("can't handle OPEN or CLOSE message!\n"); + return MMSYSERR_NOTSUPPORTED; + } + return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); +} + +typedef struct WINE_MIDIStream { + HMIDIOUT hDevice; + HANDLE hThread; + DWORD dwThreadID; + DWORD dwTempo; + DWORD dwTimeDiv; + DWORD dwPositionMS; + DWORD dwPulses; + DWORD dwStartTicks; + WORD wFlags; + HANDLE hEvent; + LPMIDIHDR lpMidiHdr; +} WINE_MIDIStream; + +#define WINE_MSM_HEADER (WM_USER+0) +#define WINE_MSM_STOP (WM_USER+1) + +/************************************************************************** + * MMSYSTEM_GetMidiStream [internal] + */ +static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm) +{ + WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE); + + if (lplpwm) + *lplpwm = lpwm; + + if (lpwm == NULL) { + return FALSE; + } + + *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID; + + return *lpMidiStrm != NULL; +} + +/************************************************************************** + * MMSYSTEM_MidiStream_Convert [internal] + */ +static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse) +{ + DWORD ret = 0; + + if (lpMidiStrm->dwTimeDiv == 0) { + FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n"); + } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */ + int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */ + int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */ + ret = (pulse * 1000) / (nf * nsf); + } else { + ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) / + (double)lpMidiStrm->dwTimeDiv); + } + + return ret; +} + +/************************************************************************** + * MMSYSTEM_MidiStream_MessageHandler [internal] + */ +static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg) +{ + LPMIDIHDR lpMidiHdr; + LPMIDIHDR* lpmh; + LPBYTE lpData; + + switch (msg->message) { + case WM_QUIT: + SetEvent(lpMidiStrm->hEvent); + return FALSE; + case WINE_MSM_STOP: + TRACE("STOP\n"); + /* this is not quite what MS doc says... */ + midiOutReset(lpMidiStrm->hDevice); + /* empty list of already submitted buffers */ + for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) { + lpMidiHdr->dwFlags |= MHDR_DONE; + lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; + + DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, + (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, + lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L); + } + lpMidiStrm->lpMidiHdr = 0; + SetEvent(lpMidiStrm->hEvent); + break; + case WINE_MSM_HEADER: + /* sets initial tick count for first MIDIHDR */ + if (!lpMidiStrm->dwStartTicks) + lpMidiStrm->dwStartTicks = GetTickCount(); + + /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent + * by native mcimidi, it doesn't look like a correct one". + * this trick allows to throw it away... but I don't like it. + * It looks like part of the file I'm trying to play and definitively looks + * like raw midi content + * I'd really like to understand why native mcimidi sends it. Perhaps a bad + * synchronization issue where native mcimidi is still processing raw MIDI + * content before generating MIDIEVENTs ? + * + * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^.. + * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b.. + * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^. + * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x. + * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^ + * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b + * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..# + * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L.. + * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H.. + * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?. + * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E. + * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F + * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H + * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.; + * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.; + * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|. + * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|. + */ + lpMidiHdr = (LPMIDIHDR)msg->lParam; + lpData = lpMidiHdr->lpData; + TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n", + (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr, + (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded, + lpMidiHdr->dwFlags, msg->wParam); +#if 0 + /* dumps content of lpMidiHdr->lpData + * FIXME: there should be a debug routine somewhere that already does this + * I hate spreading this type of shit all around the code + */ + for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) { + DWORD i; + BYTE ch; + + for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) + printf("%02x ", lpData[dwToGo + i]); + for (; i < 16; i++) + printf(" "); + for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) { + ch = lpData[dwToGo + i]; + printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.'); + } + printf("\n"); + } +#endif + if (((LPMIDIEVENT)lpData)->dwStreamID != 0 && + ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF && + ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) { + FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n", + (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", + ((LPMIDIEVENT)lpData)->dwStreamID); + lpMidiHdr->dwFlags |= MHDR_DONE; + lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; + + DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, + (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, + lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L); + break; + } + + for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext)); + *lpmh = lpMidiHdr; + lpMidiHdr = (LPMIDIHDR)msg->lParam; + lpMidiHdr->lpNext = 0; + lpMidiHdr->dwFlags |= MHDR_INQUEUE; + lpMidiHdr->dwFlags &= MHDR_DONE; + lpMidiHdr->dwOffset = 0; + + break; + default: + FIXME("Unknown message %d\n", msg->message); + break; + } + return TRUE; +} + +/************************************************************************** + * MMSYSTEM_MidiStream_Player [internal] + */ +static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt) +{ + WINE_MIDIStream* lpMidiStrm = pmt; + WINE_MIDI* lpwm; + MSG msg; + DWORD dwToGo; + DWORD dwCurrTC; + LPMIDIHDR lpMidiHdr; + LPMIDIEVENT me; + LPBYTE lpData = 0; + + TRACE("(%p)!\n", lpMidiStrm); + + if (!lpMidiStrm || + (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL) + goto the_end; + + /* force thread's queue creation */ + /* Used to be InitThreadInput16(0, 5); */ + /* but following works also with hack in midiStreamOpen */ + PeekMessageA(&msg, 0, 0, 0, 0); + + /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */ + SetEvent(lpMidiStrm->hEvent); + TRACE("Ready to go 1\n"); + /* thread is started in paused mode */ + SuspendThread(lpMidiStrm->hThread); + TRACE("Ready to go 2\n"); + + lpMidiStrm->dwStartTicks = 0; + lpMidiStrm->dwPulses = 0; + + lpMidiStrm->lpMidiHdr = 0; + + for (;;) { + lpMidiHdr = lpMidiStrm->lpMidiHdr; + if (!lpMidiHdr) { + /* for first message, block until one arrives, then process all that are available */ + GetMessageA(&msg, 0, 0, 0); + do { + if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg)) + goto the_end; + } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)); + lpData = 0; + continue; + } + + if (!lpData) + lpData = lpMidiHdr->lpData; + + me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset); + + /* do we have to wait ? */ + if (me->dwDeltaTime) { + lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime); + lpMidiStrm->dwPulses += me->dwDeltaTime; + + dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS; + + TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime); + while ((dwCurrTC = GetTickCount()) < dwToGo) { + if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) { + /* got a message, handle it */ + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { + if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg)) + goto the_end; + } + lpData = 0; + } else { + /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */ + break; + } + } + } + switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) { + case MEVT_COMMENT: + FIXME("NIY: MEVT_COMMENT\n"); + /* do nothing, skip bytes */ + break; + case MEVT_LONGMSG: + FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n"); + break; + case MEVT_NOP: + break; + case MEVT_SHORTMSG: + midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent)); + break; + case MEVT_TEMPO: + lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent); + break; + case MEVT_VERSION: + break; + default: + FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)); + break; + } + if (me->dwEvent & MEVT_F_CALLBACK) { + DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, + (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB, + lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L); + } + lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms); + if (me->dwEvent & MEVT_F_LONG) + lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3; + if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) { + /* done with this header */ + lpMidiHdr->dwFlags |= MHDR_DONE; + lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; + + lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext; + DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, + (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, + lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L); + lpData = 0; + } + } +the_end: + TRACE("End of thread\n"); + ExitThread(0); + return 0; /* for removing the warning, never executed */ +} + +/************************************************************************** + * MMSYSTEM_MidiStream_PostMessage [internal] + */ +static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2) +{ + if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) { + DWORD count; + + ReleaseThunkLock(&count); + WaitForSingleObject(lpMidiStrm->hEvent, INFINITE); + RestoreThunkLock(count); + } else { + WARN("bad PostThreadMessageA\n"); + return FALSE; + } + return TRUE; +} + +/************************************************************************** + * midiStreamClose [WINMM.@] + */ +MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm) +{ + WINE_MIDIStream* lpMidiStrm; + + TRACE("(%p)!\n", hMidiStrm); + + if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) + return MMSYSERR_INVALHANDLE; + + midiStreamStop(hMidiStrm); + MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0); + HeapFree(GetProcessHeap(), 0, lpMidiStrm); + CloseHandle(lpMidiStrm->hEvent); + + return midiOutClose((HMIDIOUT)hMidiStrm); +} + +/************************************************************************** + * MMSYSTEM_MidiStream_Open [internal] + */ +MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, DWORD cMidi, + DWORD dwCallback, DWORD dwInstance, DWORD fdwOpen, + BOOL bFrom32) +{ + WINE_MIDIStream* lpMidiStrm; + MMRESULT ret; + MIDIOPENSTRMID mosm; + LPWINE_MIDI lpwm; + HMIDIOUT hMidiOut; + + TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n", + lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen); + + if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL) + return MMSYSERR_INVALPARAM; + + lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream)); + if (!lpMidiStrm) + return MMSYSERR_NOMEM; + + lpMidiStrm->dwTempo = 500000; + lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/ + lpMidiStrm->dwPositionMS = 0; + + mosm.dwStreamID = (DWORD)lpMidiStrm; + /* FIXME: the correct value is not allocated yet for MAPPER */ + mosm.wDeviceID = *lpuDeviceID; + lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32); + lpMidiStrm->hDevice = hMidiOut; + if (lphMidiStrm) + *lphMidiStrm = (HMIDISTRM)hMidiOut; + + /* FIXME: is lpuDevice initialized upon entering midiStreamOpen ? */ + FIXME("*lpuDeviceID=%x\n", *lpuDeviceID); + lpwm->mld.uDeviceID = *lpuDeviceID = 0; + + ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen); + lpMidiStrm->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + lpMidiStrm->wFlags = HIWORD(fdwOpen); + + lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player, + lpMidiStrm, 0, &(lpMidiStrm->dwThreadID)); + + if (!lpMidiStrm->hThread) { + midiStreamClose((HMIDISTRM)hMidiOut); + return MMSYSERR_NOMEM; + } + + /* wait for thread to have started, and for its queue to be created */ + { + DWORD count; + + /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code, + * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running + * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue. + */ + ReleaseThunkLock(&count); + WaitForSingleObject(lpMidiStrm->hEvent, INFINITE); + RestoreThunkLock(count); + } + + TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n", + *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm); + return ret; +} + +/************************************************************************** + * midiStreamOpen [WINMM.@] + */ +MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, + DWORD cMidi, DWORD dwCallback, + DWORD dwInstance, DWORD fdwOpen) +{ + return MIDI_StreamOpen(lphMidiStrm, lpuDeviceID, cMidi, dwCallback, + dwInstance, fdwOpen, TRUE); +} + +/************************************************************************** + * midiStreamOut [WINMM.@] + */ +MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr, + UINT cbMidiHdr) +{ + WINE_MIDIStream* lpMidiStrm; + DWORD ret = MMSYSERR_NOERROR; + + TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr); + + if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { + ret = MMSYSERR_INVALHANDLE; + } else if (!lpMidiHdr) { + ret = MMSYSERR_INVALPARAM; + } else { + if (!PostThreadMessageA(lpMidiStrm->dwThreadID, + WINE_MSM_HEADER, cbMidiHdr, + (DWORD)lpMidiHdr)) { + WARN("bad PostThreadMessageA\n"); + ret = MMSYSERR_ERROR; + } + } + return ret; +} + +/************************************************************************** + * midiStreamPause [WINMM.@] + */ +MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm) +{ + WINE_MIDIStream* lpMidiStrm; + DWORD ret = MMSYSERR_NOERROR; + + TRACE("(%p)!\n", hMidiStrm); + + if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { + ret = MMSYSERR_INVALHANDLE; + } else { + if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) { + WARN("bad Suspend (%ld)\n", GetLastError()); + ret = MMSYSERR_ERROR; + } + } + return ret; +} + +/************************************************************************** + * midiStreamPosition [WINMM.@] + */ +MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt) +{ + WINE_MIDIStream* lpMidiStrm; + DWORD ret = MMSYSERR_NOERROR; + + TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt); + + if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { + ret = MMSYSERR_INVALHANDLE; + } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) { + ret = MMSYSERR_INVALPARAM; + } else { + switch (lpMMT->wType) { + case TIME_MS: + lpMMT->u.ms = lpMidiStrm->dwPositionMS; + TRACE("=> %ld ms\n", lpMMT->u.ms); + break; + case TIME_TICKS: + lpMMT->u.ticks = lpMidiStrm->dwPulses; + TRACE("=> %ld ticks\n", lpMMT->u.ticks); + break; + default: + WARN("Unsupported time type %d\n", lpMMT->wType); + lpMMT->wType = TIME_MS; + ret = MMSYSERR_INVALPARAM; + break; + } + } + return ret; +} + +/************************************************************************** + * midiStreamProperty [WINMM.@] + */ +MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty) +{ + WINE_MIDIStream* lpMidiStrm; + MMRESULT ret = MMSYSERR_NOERROR; + + TRACE("(%p, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty); + + if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { + ret = MMSYSERR_INVALHANDLE; + } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) { + ret = MMSYSERR_INVALPARAM; + } else if (dwProperty & MIDIPROP_TEMPO) { + MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData; + + if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) { + ret = MMSYSERR_INVALPARAM; + } else if (dwProperty & MIDIPROP_SET) { + lpMidiStrm->dwTempo = mpt->dwTempo; + TRACE("Setting tempo to %ld\n", mpt->dwTempo); + } else if (dwProperty & MIDIPROP_GET) { + mpt->dwTempo = lpMidiStrm->dwTempo; + TRACE("Getting tempo <= %ld\n", mpt->dwTempo); + } + } else if (dwProperty & MIDIPROP_TIMEDIV) { + MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData; + + if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) { + ret = MMSYSERR_INVALPARAM; + } else if (dwProperty & MIDIPROP_SET) { + lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv; + TRACE("Setting time div to %ld\n", mptd->dwTimeDiv); + } else if (dwProperty & MIDIPROP_GET) { + mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv; + TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv); + } + } else { + ret = MMSYSERR_INVALPARAM; + } + + return ret; +} + +/************************************************************************** + * midiStreamRestart [WINMM.@] + */ +MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm) +{ + WINE_MIDIStream* lpMidiStrm; + MMRESULT ret = MMSYSERR_NOERROR; + + TRACE("(%p)!\n", hMidiStrm); + + if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { + ret = MMSYSERR_INVALHANDLE; + } else { + DWORD ret; + + /* since we increase the thread suspend count on each midiStreamPause + * there may be a need for several midiStreamResume + */ + do { + ret = ResumeThread(lpMidiStrm->hThread); + } while (ret != 0xFFFFFFFF && ret != 0); + if (ret == 0xFFFFFFFF) { + WARN("bad Resume (%ld)\n", GetLastError()); + ret = MMSYSERR_ERROR; + } else { + lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS; + } + } + return ret; +} + +/************************************************************************** + * midiStreamStop [WINMM.@] + */ +MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm) +{ + WINE_MIDIStream* lpMidiStrm; + MMRESULT ret = MMSYSERR_NOERROR; + + TRACE("(%p)!\n", hMidiStrm); + + if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { + ret = MMSYSERR_INVALHANDLE; + } else { + /* in case stream has been paused... FIXME is the current state correct ? */ + midiStreamRestart(hMidiStrm); + MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0); + } + return ret; +} + +UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType, + LPCWAVEFORMATEX lpFormat, DWORD dwCallback, + DWORD dwInstance, DWORD dwFlags, BOOL bFrom32) +{ + HANDLE handle; + LPWINE_MLD wmld; + DWORD dwRet = MMSYSERR_NOERROR; + WAVEOPENDESC wod; + + TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n", + lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback, + dwInstance, dwFlags, bFrom32?32:16); + + if (dwFlags & WAVE_FORMAT_QUERY) TRACE("WAVE_FORMAT_QUERY requested !\n"); + + if (lpFormat == NULL) return WAVERR_BADFORMAT; + if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1)) + return MMSYSERR_INVALPARAM; + + TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u\n", + lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec, + lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample, lpFormat->cbSize); + + if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle, + &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL) + return MMSYSERR_NOMEM; + + wod.hWave = handle; + wod.lpFormat = lpFormat; /* should the struct be copied iso pointer? */ + wod.dwCallback = dwCallback; + wod.dwInstance = dwInstance; + wod.dnDevNode = 0L; + + TRACE("cb=%08lx\n", wod.dwCallback); + + for (;;) { + if (dwFlags & WAVE_MAPPED) { + wod.uMappedDeviceID = uDeviceID; + uDeviceID = WAVE_MAPPER; + } else { + wod.uMappedDeviceID = -1; + } + wmld->uDeviceID = uDeviceID; + + dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN, + (DWORD)&wod, dwFlags); + + if (dwRet != WAVERR_BADFORMAT || + (dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) break; + /* if we ask for a format which isn't supported by the physical driver, + * let's try to map it through the wave mapper (except, if we already tried + * or user didn't allow us to use acm codecs) + */ + dwFlags |= WAVE_MAPPED; + /* we shall loop only one */ + } + + if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) { + MMDRV_Free(handle, wmld); + handle = 0; + } + + if (lphndl != NULL) *lphndl = handle; + TRACE("=> %ld hWave=%p\n", dwRet, handle); + + return dwRet; +} + +/************************************************************************** + * waveOutGetNumDevs [WINMM.@] + */ +UINT WINAPI waveOutGetNumDevs(void) +{ + return MMDRV_GetNum(MMDRV_WAVEOUT); +} + +/************************************************************************** + * waveOutGetDevCapsA [WINMM.@] + */ +UINT WINAPI waveOutGetDevCapsA(UINT uDeviceID, LPWAVEOUTCAPSA lpCaps, + UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize); + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL) + return MMSYSERR_BADDEVICEID; + + return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE); + +} + +/************************************************************************** + * waveOutGetDevCapsW [WINMM.@] + */ +UINT WINAPI waveOutGetDevCapsW(UINT uDeviceID, LPWAVEOUTCAPSW lpCaps, + UINT uSize) +{ + WAVEOUTCAPSA wocA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA)); + + if (ret == MMSYSERR_NOERROR) { + lpCaps->wMid = wocA.wMid; + lpCaps->wPid = wocA.wPid; + lpCaps->vDriverVersion = wocA.vDriverVersion; + MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, lpCaps->szPname, + sizeof(lpCaps->szPname)/sizeof(WCHAR) ); + lpCaps->dwFormats = wocA.dwFormats; + lpCaps->wChannels = wocA.wChannels; + lpCaps->dwSupport = wocA.dwSupport; + } + return ret; +} + +/************************************************************************** + * WAVE_GetErrorText [internal] + */ +static UINT16 WAVE_GetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize) +{ + UINT16 ret = MMSYSERR_BADERRNUM; + + if (lpText == NULL) { + ret = MMSYSERR_INVALPARAM; + } else if (uSize == 0) { + ret = MMSYSERR_NOERROR; + } else if ( + /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit + * a warning for the test was always true */ + (/*uError >= MMSYSERR_BASE && */uError <= MMSYSERR_LASTERROR) || + (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) { + + if (LoadStringA(WINMM_IData->hWinMM32Instance, + uError, lpText, uSize) > 0) { + ret = MMSYSERR_NOERROR; + } + } + return ret; +} + +/************************************************************************** + * waveOutGetErrorTextA [WINMM.@] + */ +UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize) +{ + return WAVE_GetErrorText(uError, lpText, uSize); +} + +/************************************************************************** + * waveOutGetErrorTextW [WINMM.@] + */ +UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize) +{ + LPSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize); + UINT ret = WAVE_GetErrorText(uError, xstr, uSize); + + MultiByteToWideChar( CP_ACP, 0, xstr, -1, lpText, uSize ); + HeapFree(GetProcessHeap(), 0, xstr); + return ret; +} + +/************************************************************************** + * waveOutOpen [WINMM.@] + * All the args/structs have the same layout as the win16 equivalents + */ +MMRESULT WINAPI waveOutOpen(HWAVEOUT* lphWaveOut, UINT uDeviceID, + LPCWAVEFORMATEX lpFormat, DWORD dwCallback, + DWORD dwInstance, DWORD dwFlags) +{ + return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat, + dwCallback, dwInstance, dwFlags, TRUE); +} + +/************************************************************************** + * waveOutClose [WINMM.@] + */ +UINT WINAPI waveOutClose(HWAVEOUT hWaveOut) +{ + LPWINE_MLD wmld; + DWORD dwRet; + + TRACE("(%p)\n", hWaveOut); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + dwRet = MMDRV_Close(wmld, WODM_CLOSE); + MMDRV_Free(hWaveOut, wmld); + + return dwRet; +} + +/************************************************************************** + * waveOutPrepareHeader [WINMM.@] + */ +UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut, + WAVEHDR* lpWaveOutHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); + + if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_PREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE); +} + +/************************************************************************** + * waveOutUnprepareHeader [WINMM.@] + */ +UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut, + LPWAVEHDR lpWaveOutHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); + + if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD)lpWaveOutHdr, uSize, TRUE); +} + +/************************************************************************** + * waveOutWrite [WINMM.@] + */ +UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, + UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_WRITE, (DWORD)lpWaveOutHdr, uSize, TRUE); +} + +/************************************************************************** + * waveOutBreakLoop [WINMM.@] + */ +UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut) +{ + LPWINE_MLD wmld; + + TRACE("(%p);\n", hWaveOut); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE); +} + +/************************************************************************** + * waveOutPause [WINMM.@] + */ +UINT WINAPI waveOutPause(HWAVEOUT hWaveOut) +{ + LPWINE_MLD wmld; + + TRACE("(%p);\n", hWaveOut); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE); +} + +/************************************************************************** + * waveOutReset [WINMM.@] + */ +UINT WINAPI waveOutReset(HWAVEOUT hWaveOut) +{ + LPWINE_MLD wmld; + + TRACE("(%p);\n", hWaveOut); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE); +} + +/************************************************************************** + * waveOutRestart [WINMM.@] + */ +UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut) +{ + LPWINE_MLD wmld; + + TRACE("(%p);\n", hWaveOut); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE); +} + +/************************************************************************** + * waveOutGetPosition [WINMM.@] + */ +UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime, + UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_GETPOS, (DWORD)lpTime, uSize, TRUE); +} + +/************************************************************************** + * waveOutGetPitch [WINMM.@] + */ +UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD)lpdw, 0L, TRUE); +} + +/************************************************************************** + * waveOutSetPitch [WINMM.@] + */ +UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE); +} + +/************************************************************************** + * waveOutGetPlaybackRate [WINMM.@] + */ +UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD)lpdw, 0L, TRUE); +} + +/************************************************************************** + * waveOutSetPlaybackRate [WINMM.@] + */ +UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE); +} + +/************************************************************************** + * waveOutGetVolume [WINMM.@] + */ +UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD)lpdw, 0L, TRUE); +} + +/************************************************************************** + * waveOutSetVolume [WINMM.@] + */ +UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %08lx);\n", hWaveOut, dw); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE); +} + +/************************************************************************** + * waveOutGetID [WINMM.@] + */ +UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + return 0; +} + +/************************************************************************** + * waveOutMessage [WINMM.@] + */ +DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage, + DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) { + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) { + return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); + } + return MMSYSERR_INVALHANDLE; + } + + /* from M$ KB */ + if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) + return MMSYSERR_INVALPARAM; + + return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); +} + +/************************************************************************** + * waveInGetNumDevs [WINMM.@] + */ +UINT WINAPI waveInGetNumDevs(void) +{ + return MMDRV_GetNum(MMDRV_WAVEIN); +} + +/************************************************************************** + * waveInGetDevCapsW [WINMM.@] + */ +UINT WINAPI waveInGetDevCapsW(UINT uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize) +{ + WAVEINCAPSA wicA; + UINT ret = waveInGetDevCapsA(uDeviceID, &wicA, uSize); + + if (ret == MMSYSERR_NOERROR) { + lpCaps->wMid = wicA.wMid; + lpCaps->wPid = wicA.wPid; + lpCaps->vDriverVersion = wicA.vDriverVersion; + MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, lpCaps->szPname, + sizeof(lpCaps->szPname)/sizeof(WCHAR) ); + lpCaps->dwFormats = wicA.dwFormats; + lpCaps->wChannels = wicA.wChannels; + } + + return ret; +} + +/************************************************************************** + * waveInGetDevCapsA [WINMM.@] + */ +UINT WINAPI waveInGetDevCapsA(UINT uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize); + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL) + return MMSYSERR_BADDEVICEID; + + return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD)lpCaps, uSize, TRUE); +} + +/************************************************************************** + * waveInGetErrorTextA [WINMM.@] + */ +UINT WINAPI waveInGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize) +{ + return WAVE_GetErrorText(uError, lpText, uSize); +} + +/************************************************************************** + * waveInGetErrorTextW [WINMM.@] + */ +UINT WINAPI waveInGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize) +{ + LPSTR txt = HeapAlloc(GetProcessHeap(), 0, uSize); + UINT ret = WAVE_GetErrorText(uError, txt, uSize); + + MultiByteToWideChar( CP_ACP, 0, txt, -1, lpText, uSize ); + HeapFree(GetProcessHeap(), 0, txt); + return ret; +} + +/************************************************************************** + * waveInOpen [WINMM.@] + */ +MMRESULT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID, + LPCWAVEFORMATEX lpFormat, DWORD dwCallback, + DWORD dwInstance, DWORD dwFlags) +{ + return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat, + dwCallback, dwInstance, dwFlags, TRUE); +} + +/************************************************************************** + * waveInClose [WINMM.@] + */ +UINT WINAPI waveInClose(HWAVEIN hWaveIn) +{ + LPWINE_MLD wmld; + DWORD dwRet; + + TRACE("(%p)\n", hWaveIn); + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE); + MMDRV_Free(hWaveIn, wmld); + return dwRet; +} + +/************************************************************************** + * waveInPrepareHeader [WINMM.@] + */ +UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr, + UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); + + if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM; + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + lpWaveInHdr->dwBytesRecorded = 0; + + return MMDRV_Message(wmld, WIDM_PREPARE, (DWORD)lpWaveInHdr, uSize, TRUE); +} + +/************************************************************************** + * waveInUnprepareHeader [WINMM.@] + */ +UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr, + UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); + + if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM; + if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD)lpWaveInHdr, uSize, TRUE); +} + +/************************************************************************** + * waveInAddBuffer [WINMM.@] + */ +UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn, + WAVEHDR* lpWaveInHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); + + if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM; + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD)lpWaveInHdr, uSize, TRUE); +} + +/************************************************************************** + * waveInReset [WINMM.@] + */ +UINT WINAPI waveInReset(HWAVEIN hWaveIn) +{ + LPWINE_MLD wmld; + + TRACE("(%p);\n", hWaveIn); + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE); +} + +/************************************************************************** + * waveInStart [WINMM.@] + */ +UINT WINAPI waveInStart(HWAVEIN hWaveIn) +{ + LPWINE_MLD wmld; + + TRACE("(%p);\n", hWaveIn); + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE); +} + +/************************************************************************** + * waveInStop [WINMM.@] + */ +UINT WINAPI waveInStop(HWAVEIN hWaveIn) +{ + LPWINE_MLD wmld; + + TRACE("(%p);\n", hWaveIn); + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE); +} + +/************************************************************************** + * waveInGetPosition [WINMM.@] + */ +UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime, + UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize); + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD)lpTime, uSize, TRUE); +} + +/************************************************************************** + * waveInGetID [WINMM.@] + */ +UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * waveInMessage [WINMM.@] + */ +DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage, + DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) { + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) { + return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); + } + return MMSYSERR_INVALHANDLE; + } + + /* from M$ KB */ + if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) + return MMSYSERR_INVALPARAM; + + + return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); +} + diff --git a/reactos/lib/winmm/winmm.rc b/reactos/lib/winmm/winmm.rc index c3b31d02220..61cccbc9510 100644 --- a/reactos/lib/winmm/winmm.rc +++ b/reactos/lib/winmm/winmm.rc @@ -8,7 +8,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US /* * These strings are exactly as the original winmm's. I think we might be * able to improve on them, as most of them are meaningless to the end - * user! + * user! Also, translations need to be done */ STRINGTABLE