diff --git a/reactos/lib/winmm/Makefile b/reactos/lib/winmm/Makefile new file mode 100644 index 00000000000..5529fb2176c --- /dev/null +++ b/reactos/lib/winmm/Makefile @@ -0,0 +1,9 @@ +# $Id: Makefile 8376 2004-02-25 20:00:42Z sedwards $ + +PATH_TO_TOP = ../.. + +TARGET_TYPE = winedll + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk diff --git a/reactos/lib/winmm/Makefile.in b/reactos/lib/winmm/Makefile.in new file mode 100644 index 00000000000..de41d268018 --- /dev/null +++ b/reactos/lib/winmm/Makefile.in @@ -0,0 +1,34 @@ +EXTRADEFS = -D_WINMM_ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = winmm.dll +IMPORTS = user32 advapi32 kernel32 ntdll + +C_SRCS = \ + driver.c \ + joystick.c \ + lolvldrv.c \ + mci.c \ + mmio.c \ + playsound.c \ + time.c \ + winmm.c + +C_SRCS16 = \ + message16.c \ + mmsystem.c \ + sound16.c + +SPEC_SRCS16 = \ + mmsystem.spec \ + sound.spec + +RC_SRCS = winmm_res.rc + +SUBDIRS = tests + +@MAKE_DLL_RULES@ + +### Dependencies: diff --git a/reactos/lib/winmm/Makefile.ros-template b/reactos/lib/winmm/Makefile.ros-template new file mode 100644 index 00000000000..68f3e03dfea --- /dev/null +++ b/reactos/lib/winmm/Makefile.ros-template @@ -0,0 +1,21 @@ +# $Id: Makefile.ros-template 11910 2004-12-03 23:37:44Z blight $ + +TARGET_NAME = winmm + +TARGET_OBJECTS = @C_SRCS@ + +TARGET_CFLAGS = @EXTRADEFS@ -D__REACTOS__ + +TARGET_SDKLIBS = @IMPORTS@ wine.a wine_uuid.a ntdll.a + +TARGET_BASE = $(TARGET_BASE_LIB_WINMM) + +TARGET_RC_SRCS = @RC_SRCS@ +TARGET_RC_BINSRC = @RC_BINSRC@ +TARGET_RC_BINARIES = @RC_BINARIES@ + +default: all + +DEP_OBJECTS = $(TARGET_OBJECTS) + +include $(TOOLS_PATH)/depend.mk diff --git a/reactos/lib/winmm/driver.c b/reactos/lib/winmm/driver.c new file mode 100644 index 00000000000..7c254549751 --- /dev/null +++ b/reactos/lib/winmm/driver.c @@ -0,0 +1,567 @@ +/* -*- 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 + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "winreg.h" +#include "mmddk.h" +#include "winemm.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(driver); + +#define HKLM_BASE "Software\\Microsoft\\Windows NT\\CurrentVersion" + +static LPWINE_DRIVER lpDrvItemList /* = NULL */; + +WINE_MMTHREAD* (*pFnGetMMThread16)(UINT16 h) /* = NULL */; +LPWINE_DRIVER (*pFnOpenDriver16)(LPCSTR,LPCSTR,LPARAM) /* = NULL */; +LRESULT (*pFnCloseDriver16)(UINT16,LPARAM,LPARAM) /* = NULL */; +LRESULT (*pFnSendMessage16)(UINT16,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) +{ + HKEY hKey, hSecKey; + DWORD bufLen, lRet; + + lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, HKLM_BASE, 0, KEY_QUERY_VALUE, &hKey); + if (lRet == ERROR_SUCCESS) { + lRet = RegOpenKeyExA(hKey, sectName, 0, KEY_QUERY_VALUE, &hSecKey); + if (lRet == ERROR_SUCCESS) { + lRet = RegQueryValueExA(hSecKey, keyName, 0, 0, buf, &bufLen); + RegCloseKey( hSecKey ); + } + RegCloseKey( hKey ); + } + if (lRet == ERROR_SUCCESS) return TRUE; + /* default to system.ini if we can't find it in the registry, + * to support native installations where system.ini is still used */ + 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) +{ + INT len; + LPSTR dn = NULL; + LPSTR sn = NULL; + HDRVR ret; + + if (lpDriverName) + { + len = WideCharToMultiByte( CP_ACP, 0, lpDriverName, -1, NULL, 0, NULL, NULL ); + dn = HeapAlloc( GetProcessHeap(), 0, len ); + if (!dn) return 0; + WideCharToMultiByte( CP_ACP, 0, lpDriverName, -1, dn, len, NULL, NULL ); + } + + if (lpSectionName) + { + len = WideCharToMultiByte( CP_ACP, 0, lpSectionName, -1, NULL, 0, NULL, NULL ); + sn = HeapAlloc( GetProcessHeap(), 0, len ); + if (!sn) return 0; + WideCharToMultiByte( CP_ACP, 0, lpSectionName, -1, sn, len, NULL, NULL ); + } + + 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(lpDrv0->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_PTR 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/joystick.c b/reactos/lib/winmm/joystick.c new file mode 100644 index 00000000000..d1957082f4a --- /dev/null +++ b/reactos/lib/winmm/joystick.c @@ -0,0 +1,309 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ +/* + * joystick functions + * + * Copyright 1997 Andreas Mohr + * 2000 Wolfgang Schwotzer + * 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 + */ + +#include "config.h" + +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "winemm.h" + +#include "mmddk.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winmm); + +#define MAXJOYSTICK (JOYSTICKID2 + 1) +#define JOY_PERIOD_MIN (10) /* min Capture time period */ +#define JOY_PERIOD_MAX (1000) /* max Capture time period */ + +typedef struct tagWINE_JOYSTICK { + JOYINFO ji; + HWND hCapture; + UINT wTimer; + DWORD threshold; + BOOL bChanged; + HDRVR hDriver; +} WINE_JOYSTICK; + +static WINE_JOYSTICK JOY_Sticks[MAXJOYSTICK]; + +/************************************************************************** + * JOY_LoadDriver [internal] + */ +static BOOL JOY_LoadDriver(DWORD dwJoyID) +{ + if (dwJoyID >= MAXJOYSTICK) + return FALSE; + if (JOY_Sticks[dwJoyID].hDriver) + return TRUE; + + JOY_Sticks[dwJoyID].hDriver = OpenDriverA("joystick.drv", 0, dwJoyID); + return (JOY_Sticks[dwJoyID].hDriver != 0); +} + +/************************************************************************** + * JOY_Timer [internal] + */ +static void CALLBACK JOY_Timer(HWND hWnd, UINT wMsg, UINT wTimer, DWORD dwTime) +{ + int i; + WINE_JOYSTICK* joy; + JOYINFO ji; + LONG pos; + unsigned buttonChange; + + for (i = 0; i < MAXJOYSTICK; i++) { + joy = &JOY_Sticks[i]; + + if (joy->hCapture != hWnd) continue; + + joyGetPos(i, &ji); + pos = MAKELONG(ji.wXpos, ji.wYpos); + + if (!joy->bChanged || + abs(joy->ji.wXpos - ji.wXpos) > joy->threshold || + abs(joy->ji.wYpos - ji.wYpos) > joy->threshold) { + SendMessageA(joy->hCapture, MM_JOY1MOVE + i, ji.wButtons, pos); + joy->ji.wXpos = ji.wXpos; + joy->ji.wYpos = ji.wYpos; + } + if (!joy->bChanged || + abs(joy->ji.wZpos - ji.wZpos) > joy->threshold) { + SendMessageA(joy->hCapture, MM_JOY1ZMOVE + i, ji.wButtons, pos); + joy->ji.wZpos = ji.wZpos; + } + if ((buttonChange = joy->ji.wButtons ^ ji.wButtons) != 0) { + if (ji.wButtons & buttonChange) + SendMessageA(joy->hCapture, MM_JOY1BUTTONDOWN + i, + (buttonChange << 8) | (ji.wButtons & buttonChange), pos); + if (joy->ji.wButtons & buttonChange) + SendMessageA(joy->hCapture, MM_JOY1BUTTONUP + i, + (buttonChange << 8) | (joy->ji.wButtons & buttonChange), pos); + joy->ji.wButtons = ji.wButtons; + } + } +} + +/************************************************************************** + * joyGetNumDevs [WINMM.@] + */ +UINT WINAPI joyGetNumDevs(void) +{ + UINT ret = 0; + int i; + + for (i = 0; i < MAXJOYSTICK; i++) { + if (JOY_LoadDriver(i)) { + ret += SendDriverMessage(JOY_Sticks[i].hDriver, JDD_GETNUMDEVS, 0L, 0L); + } + } + return ret; +} + +/************************************************************************** + * joyGetDevCapsA [WINMM.@] + */ +MMRESULT WINAPI joyGetDevCapsA(UINT_PTR wID, LPJOYCAPSA lpCaps, UINT wSize) +{ + if (wID >= MAXJOYSTICK) return JOYERR_PARMS; + if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; + + lpCaps->wPeriodMin = JOY_PERIOD_MIN; /* FIXME */ + lpCaps->wPeriodMax = JOY_PERIOD_MAX; /* FIXME (same as MS Joystick Driver) */ + + return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETDEVCAPS, (DWORD)lpCaps, wSize); +} + +/************************************************************************** + * joyGetDevCapsW [WINMM.@] + */ +MMRESULT WINAPI joyGetDevCapsW(UINT_PTR wID, LPJOYCAPSW lpCaps, UINT wSize) +{ + JOYCAPSA jca; + MMRESULT ret = joyGetDevCapsA(wID, &jca, sizeof(jca)); + + if (ret != JOYERR_NOERROR) return ret; + lpCaps->wMid = jca.wMid; + lpCaps->wPid = jca.wPid; + MultiByteToWideChar( CP_ACP, 0, jca.szPname, -1, lpCaps->szPname, + sizeof(lpCaps->szPname)/sizeof(WCHAR) ); + lpCaps->wXmin = jca.wXmin; + lpCaps->wXmax = jca.wXmax; + lpCaps->wYmin = jca.wYmin; + lpCaps->wYmax = jca.wYmax; + lpCaps->wZmin = jca.wZmin; + lpCaps->wZmax = jca.wZmax; + lpCaps->wNumButtons = jca.wNumButtons; + lpCaps->wPeriodMin = jca.wPeriodMin; + lpCaps->wPeriodMax = jca.wPeriodMax; + + if (wSize >= sizeof(JOYCAPSW)) { /* Win95 extensions ? */ + lpCaps->wRmin = jca.wRmin; + lpCaps->wRmax = jca.wRmax; + lpCaps->wUmin = jca.wUmin; + lpCaps->wUmax = jca.wUmax; + lpCaps->wVmin = jca.wVmin; + lpCaps->wVmax = jca.wVmax; + lpCaps->wCaps = jca.wCaps; + lpCaps->wMaxAxes = jca.wMaxAxes; + lpCaps->wNumAxes = jca.wNumAxes; + lpCaps->wMaxButtons = jca.wMaxButtons; + MultiByteToWideChar( CP_ACP, 0, jca.szRegKey, -1, lpCaps->szRegKey, + sizeof(lpCaps->szRegKey)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, jca.szOEMVxD, -1, lpCaps->szOEMVxD, + sizeof(lpCaps->szOEMVxD)/sizeof(WCHAR) ); + } + + return ret; +} + +/************************************************************************** + * joyGetPosEx [WINMM.@] + */ +MMRESULT WINAPI joyGetPosEx(UINT wID, LPJOYINFOEX lpInfo) +{ + TRACE("(%d, %p);\n", wID, lpInfo); + + if (wID >= MAXJOYSTICK) return JOYERR_PARMS; + if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; + + lpInfo->dwXpos = 0; + lpInfo->dwYpos = 0; + lpInfo->dwZpos = 0; + lpInfo->dwRpos = 0; + lpInfo->dwUpos = 0; + lpInfo->dwVpos = 0; + lpInfo->dwButtons = 0; + lpInfo->dwButtonNumber = 0; + lpInfo->dwPOV = 0; + lpInfo->dwReserved1 = 0; + lpInfo->dwReserved2 = 0; + + return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETPOSEX, (DWORD)lpInfo, 0L); +} + +/************************************************************************** + * joyGetPos [WINMM.@] + */ +MMRESULT WINAPI joyGetPos(UINT wID, LPJOYINFO lpInfo) +{ + TRACE("(%d, %p);\n", wID, lpInfo); + + if (wID >= MAXJOYSTICK) return JOYERR_PARMS; + if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; + + lpInfo->wXpos = 0; + lpInfo->wYpos = 0; + lpInfo->wZpos = 0; + lpInfo->wButtons = 0; + + return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETPOS, (DWORD)lpInfo, 0L); +} + +/************************************************************************** + * joyGetThreshold [WINMM.@] + */ +MMRESULT WINAPI joyGetThreshold(UINT wID, LPUINT lpThreshold) +{ + TRACE("(%04X, %p);\n", wID, lpThreshold); + + if (wID >= MAXJOYSTICK) return JOYERR_PARMS; + + *lpThreshold = JOY_Sticks[wID].threshold; + return JOYERR_NOERROR; +} + +/************************************************************************** + * joyReleaseCapture [WINMM.@] + */ +MMRESULT WINAPI joyReleaseCapture(UINT wID) +{ + TRACE("(%04X);\n", wID); + + if (wID >= MAXJOYSTICK) return JOYERR_PARMS; + if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; + if (!JOY_Sticks[wID].hCapture) return JOYERR_NOCANDO; + + KillTimer(JOY_Sticks[wID].hCapture, JOY_Sticks[wID].wTimer); + JOY_Sticks[wID].hCapture = 0; + JOY_Sticks[wID].wTimer = 0; + + return JOYERR_NOERROR; +} + +/************************************************************************** + * joySetCapture [WINMM.@] + */ +MMRESULT WINAPI joySetCapture(HWND hWnd, UINT wID, UINT wPeriod, BOOL bChanged) +{ + TRACE("(%p, %04X, %d, %d);\n", hWnd, wID, wPeriod, bChanged); + + if (wID >= MAXJOYSTICK || hWnd == 0) return JOYERR_PARMS; + if (wPeriodJOY_PERIOD_MAX) return JOYERR_PARMS; + if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; + + if (JOY_Sticks[wID].hCapture || !IsWindow(hWnd)) + return JOYERR_NOCANDO; /* FIXME: what should be returned ? */ + + if (joyGetPos(wID, &JOY_Sticks[wID].ji) != JOYERR_NOERROR) + return JOYERR_UNPLUGGED; + + if ((JOY_Sticks[wID].wTimer = SetTimer(hWnd, 0, wPeriod, JOY_Timer)) == 0) + return JOYERR_NOCANDO; + + JOY_Sticks[wID].hCapture = hWnd; + JOY_Sticks[wID].bChanged = bChanged; + + return JOYERR_NOERROR; +} + +/************************************************************************** + * joySetThreshold [WINMM.@] + */ +MMRESULT WINAPI joySetThreshold(UINT wID, UINT wThreshold) +{ + TRACE("(%04X, %d);\n", wID, wThreshold); + + if (wID >= MAXJOYSTICK) return MMSYSERR_INVALPARAM; + + JOY_Sticks[wID].threshold = wThreshold; + + return JOYERR_NOERROR; +} diff --git a/reactos/lib/winmm/lolvldrv.c b/reactos/lib/winmm/lolvldrv.c new file mode 100644 index 00000000000..20f9bb36d38 --- /dev/null +++ b/reactos/lib/winmm/lolvldrv.c @@ -0,0 +1,857 @@ +/* -*- 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 + */ + +#include +#include +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winver.h" +#include "winemm.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winmm); + +LRESULT (*pFnCallMMDrvFunc16)(DWORD,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 */ + LPCSTR 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[8]; +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 = um3216; + llTypes[drv].Callback = cb; +} + +/****************************************************************** + * MMDRV_Is32 + * + */ +BOOL MMDRV_Is32(unsigned int idx) +{ + TRACE("(%d)\n", 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; + FARPROC pGetFileVersionInfoSizeA; + FARPROC pGetFileVersionInfoA; + FARPROC pVerQueryValueA; + HMODULE hmodule = 0; + TRACE("(%p, %p, %d)\n", fname, buf, buflen); + +#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) +{ + TRACE("(%04x)\n", type); + assert(type < MMDRV_MAX); + return llTypes[type].wMaxId; +} + +/************************************************************************** + * MMDRV_Message [internal] + */ +DWORD MMDRV_Message(LPWINE_MLD mld, UINT wMsg, DWORD_PTR dwParam1, + DWORD_PTR 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("=> %s\n", WINMM_ErrorToString(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("=> %s\n", WINMM_ErrorToString(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((DWORD)part->u.fnMessage16, + mld->uDeviceID, wMsg, mld->dwDriverInstance, + dwParam1, dwParam2); + TRACE("=> %s\n", WINMM_ErrorToString(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((DWORD)part->u.fnMessage16, + mld->uDeviceID, wMsg, mld->dwDriverInstance, + dwParam1, dwParam2); + TRACE("=> %s\n", WINMM_ErrorToString(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; + TRACE("(%d, %04x, %p, %p, %p, %p, %c)\n", + size, type, hndl, dwFlags, dwCallback, dwInstance, bFrom32?'Y':'N'); + + 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) +{ + TRACE("(%p, %p)\n", hndl, 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]; + TRACE("(%p, %04x, 0x%08lx, 0x%08lx)\n", mld, wMsg, dwParam1, dwFlags); + + 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) +{ + TRACE("(%p, %04x)\n", mld, wMsg); + return MMDRV_Message(mld, wMsg, 0L, 0L, TRUE); +} + +/************************************************************************** + * MMDRV_GetByID [internal] + */ +LPWINE_MLD MMDRV_GetByID(UINT uDevID, UINT type) +{ + TRACE("(%04x, %04x)\n", uDevID, 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; + TRACE("(%p, %04x, %c)\n", _hndl, type, bCanBeID ? 'Y' : 'N'); + + 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; + TRACE("(%p, %04x, %c, %04x)\n", + hndl, srcType, bSrcCanBeID ? 'Y' : 'N', dstType); + + 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 DRVM_MAPPER_PREFERRED_GET: + /* FIXME: get from registry someday */ + *((LPDWORD)dwParam1) = -1; /* No preferred device */ + break; + + case DRV_QUERYDEVICEINTERFACE: + case DRV_QUERYDEVICEINTERFACESIZE: + return MMDRV_Message(mld, uMsg, dwParam1, dwParam2, TRUE); + + case DRV_QUERYDSOUNDIFACE: /* Wine-specific: Retrieve DirectSound interface */ + case DRV_QUERYDSOUNDDESC: /* Wine-specific: Retrieve DirectSound driver description*/ + 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; + TRACE("(%p, %04x, %04x)\n", lpDrv, type, wMsg); + + 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 => %s\n", WINMM_ErrorToString(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((DWORD)part->u.fnMessage16, + 0, DRVM_INIT, 0L, 0L, 0L); + TRACE("DRVM_INIT => %s\n", WINMM_ErrorToString(ret)); +#if 0 + ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, + 0, DRVM_ENABLE, 0L, 0L, 0L); + TRACE("DRVM_ENABLE => %08lx\n", ret); +#endif + count = pFnCallMMDrvFunc16((DWORD)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); + + if (HIWORD(count)) + return FALSE; + + /* 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 */ + if (llTypes[type].lpMlds) + llTypes[type].lpMlds = (LPWINE_MLD) + HeapReAlloc(GetProcessHeap(), 0, llTypes[type].lpMlds - 1, + sizeof(WINE_MLD) * (llTypes[type].wMaxId + 1)) + 1; + else + llTypes[type].lpMlds = (LPWINE_MLD) + HeapAlloc(GetProcessHeap(), 0, + 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'); + + for (i = 0; i < MMDrvsHi; i++) { + if (!strcmp(drvRegName, MMDrvs[i].drvname)) return FALSE; + } + + /* 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])); + + 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) { + 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 */ + i = 0; + if (MMDRV_InitPerType(lpDrv, MMDRV_AUX, AUXDM_GETNUMDEVS)) i = 1; + if (MMDRV_InitPerType(lpDrv, MMDRV_MIXER, MXDM_GETNUMDEVS)) i = 1; + if (MMDRV_InitPerType(lpDrv, MMDRV_MIDIIN, MIDM_GETNUMDEVS)) i = 1; + if (MMDRV_InitPerType(lpDrv, MMDRV_MIDIOUT, MODM_GETNUMDEVS)) i = 1; + if (MMDRV_InitPerType(lpDrv, MMDRV_WAVEIN, WIDM_GETNUMDEVS)) i = 1; + if (MMDRV_InitPerType(lpDrv, MMDRV_WAVEOUT, WODM_GETNUMDEVS)) i = 1; + /* if all those func calls return FALSE, then the driver must be unloaded */ + if (!i) { + CloseDriver(lpDrv->hDriver, 0, 0); + HeapFree(GetProcessHeap(), 0, lpDrv->drvname); + WARN("Driver initialization failed\n"); + return FALSE; + } + + 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; + TRACE("()\n"); + + 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) +{ + TRACE("()\n"); + /* first load hardware drivers */ +#ifndef __REACTOS__ + MMDRV_Install("wineoss.drv", "wineoss.drv", FALSE); +#endif /* __REACTOS__ */ + +#ifdef __REACTOS__ + // AG: TESTING: + MMDRV_Install("mmdrv.dll", "mmdrv.dll", FALSE); +#endif + + /* finish with mappers */ + MMDRV_Install("wavemapper", "msacm32.dll", TRUE); + MMDRV_Install("midimapper", "midimap.dll", TRUE); + + return TRUE; +} + +/************************************************************************** + * MMDRV_Init [internal] + */ +BOOL MMDRV_Init(void) +{ + TRACE("()\n"); + /* 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; + TRACE("(%p, %04x)\n", lpDrv, type); + + 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 => %s\n", WINMM_ErrorToString(ret)); + } else if (!lpDrv->bIs32 && part->u.fnMessage16 && pFnCallMMDrvFunc16) { +#if 0 + ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, + 0, DRVM_DISABLE, 0L, 0L, 0L); + TRACE("DRVM_DISABLE => %08lx\n", ret); +#endif + ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, + 0, DRVM_EXIT, 0L, 0L, 0L); + TRACE("DRVM_EXIT => %s\n", WINMM_ErrorToString(ret)); + } else { + return FALSE; + } + + return TRUE; +} + +/****************************************************************** + * Exit + * + * + */ +void MMDRV_Exit(void) +{ + int i; + TRACE("()\n"); + + 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/mci.c b/reactos/lib/winmm/mci.c new file mode 100644 index 00000000000..8d1961c263a --- /dev/null +++ b/reactos/lib/winmm/mci.c @@ -0,0 +1,1743 @@ +/* + * MCI internal functions + * + * Copyright 1998/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 + */ + +/* TODO: + * - implement WINMM (32bit) multitasking and use it in all MCI drivers + * instead of the home grown one + * - 16bit mmTaskXXX functions are currently broken because the 16 + * loader does not support binary command lines => provide Wine's + * own mmtask.tsk not using binary command line. + * - correctly handle the MCI_ALL_DEVICE_ID in functions. + * - finish mapping 16 <=> 32 of MCI structures and commands + * - implement auto-open feature (ie, when a string command is issued + * for a not yet opened device, MCI automatically opens it) + * - use a default registry setting to replace the [mci] section in + * configuration file (layout of info in registry should be compatible + * with all Windows' version - which use different layouts of course) + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winreg.h" +#include "mmsystem.h" +#include "winuser.h" +#include "winnls.h" +#include "winreg.h" + +#include "digitalv.h" +#include "winemm.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mci); + +WINMM_MapType (*pFnMciMapMsg16To32A) (WORD,WORD,DWORD*) /* = NULL */; +WINMM_MapType (*pFnMciUnMapMsg16To32A)(WORD,WORD,DWORD) /* = NULL */; +WINMM_MapType (*pFnMciMapMsg32ATo16) (WORD,WORD,DWORD,DWORD*) /* = NULL */; +WINMM_MapType (*pFnMciUnMapMsg32ATo16)(WORD,WORD,DWORD,DWORD) /* = NULL */; + +/* First MCI valid device ID (0 means error) */ +#define MCI_MAGIC 0x0001 + +/* MCI settings */ +#define HKLM_MCI "Software\\Microsoft\\Windows NT\\CurrentVersion\\MCI" + +/* dup a string and uppercase it */ +inline static LPSTR str_dup_upper( LPCSTR str ) +{ + INT len = strlen(str) + 1; + LPSTR p = HeapAlloc( GetProcessHeap(), 0, len ); + if (p) + { + memcpy( p, str, len ); + CharUpperA( p ); + } + return p; +} + +/************************************************************************** + * MCI_GetDriver [internal] + */ +LPWINE_MCIDRIVER MCI_GetDriver(UINT16 wDevID) +{ + LPWINE_MCIDRIVER wmd = 0; + + EnterCriticalSection(&WINMM_IData->cs); + for (wmd = WINMM_IData->lpMciDrvs; wmd; wmd = wmd->lpNext) { + if (wmd->wDeviceID == wDevID) + break; + } + LeaveCriticalSection(&WINMM_IData->cs); + return wmd; +} + +/************************************************************************** + * MCI_GetDriverFromString [internal] + */ +UINT MCI_GetDriverFromString(LPCSTR lpstrName) +{ + LPWINE_MCIDRIVER wmd; + UINT ret = 0; + + if (!lpstrName) + return 0; + + if (!lstrcmpiA(lpstrName, "ALL")) + return MCI_ALL_DEVICE_ID; + + EnterCriticalSection(&WINMM_IData->cs); + for (wmd = WINMM_IData->lpMciDrvs; wmd; wmd = wmd->lpNext) { + if (wmd->lpstrElementName && strcmp(wmd->lpstrElementName, lpstrName) == 0) { + ret = wmd->wDeviceID; + break; + } + if (wmd->lpstrDeviceType && strcasecmp(wmd->lpstrDeviceType, lpstrName) == 0) { + ret = wmd->wDeviceID; + break; + } + if (wmd->lpstrAlias && strcasecmp(wmd->lpstrAlias, lpstrName) == 0) { + ret = wmd->wDeviceID; + break; + } + } + LeaveCriticalSection(&WINMM_IData->cs); + + return ret; +} + +/************************************************************************** + * MCI_MessageToString [internal] + */ +const char* MCI_MessageToString(UINT16 wMsg) +{ + static char buffer[100]; + +#define CASE(s) case (s): return #s + + switch (wMsg) { + CASE(MCI_BREAK); + CASE(MCI_CLOSE); + CASE(MCI_CLOSE_DRIVER); + CASE(MCI_COPY); + CASE(MCI_CUE); + CASE(MCI_CUT); + CASE(MCI_DELETE); + CASE(MCI_ESCAPE); + CASE(MCI_FREEZE); + CASE(MCI_PAUSE); + CASE(MCI_PLAY); + CASE(MCI_GETDEVCAPS); + CASE(MCI_INFO); + CASE(MCI_LOAD); + CASE(MCI_OPEN); + CASE(MCI_OPEN_DRIVER); + CASE(MCI_PASTE); + CASE(MCI_PUT); + CASE(MCI_REALIZE); + CASE(MCI_RECORD); + CASE(MCI_RESUME); + CASE(MCI_SAVE); + CASE(MCI_SEEK); + CASE(MCI_SET); + CASE(MCI_SPIN); + CASE(MCI_STATUS); + CASE(MCI_STEP); + CASE(MCI_STOP); + CASE(MCI_SYSINFO); + CASE(MCI_UNFREEZE); + CASE(MCI_UPDATE); + CASE(MCI_WHERE); + CASE(MCI_WINDOW); + /* constants for digital video */ + CASE(MCI_CAPTURE); + CASE(MCI_MONITOR); + CASE(MCI_RESERVE); + CASE(MCI_SETAUDIO); + CASE(MCI_SIGNAL); + CASE(MCI_SETVIDEO); + CASE(MCI_QUALITY); + CASE(MCI_LIST); + CASE(MCI_UNDO); + CASE(MCI_CONFIGURE); + CASE(MCI_RESTORE); +#undef CASE + default: + sprintf(buffer, "MCI_<<%04X>>", wMsg); + return buffer; + } +} + +/************************************************************************** + * MCI_GetDevTypeFromFileName [internal] + */ +static DWORD MCI_GetDevTypeFromFileName(LPCSTR fileName, LPSTR buf, UINT len) +{ + LPSTR tmp; + HKEY hKey; + + if ((tmp = strrchr(fileName, '.'))) { + if (RegOpenKeyExA( HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\MCI Extensions", + 0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) { + DWORD dwLen = len; + LONG lRet = RegQueryValueExA( hKey, tmp + 1, 0, 0, buf, &dwLen ); + RegCloseKey( hKey ); + if (lRet == ERROR_SUCCESS) return 0; + } + TRACE("No ...\\MCI Extensions entry for '%s' found.\n", tmp); + } + return MCIERR_EXTENSION_NOT_FOUND; +} + +#define MAX_MCICMDTABLE 20 +#define MCI_COMMAND_TABLE_NOT_LOADED 0xFFFE + +typedef struct tagWINE_MCICMDTABLE { + UINT uDevType; + LPCSTR lpTable; + UINT nVerbs; /* number of verbs in command table */ + LPCSTR* aVerbs; /* array of verbs to speed up the verb look up process */ +} WINE_MCICMDTABLE, *LPWINE_MCICMDTABLE; + +static WINE_MCICMDTABLE S_MciCmdTable[MAX_MCICMDTABLE]; + +/************************************************************************** + * MCI_IsCommandTableValid [internal] + */ +static BOOL MCI_IsCommandTableValid(UINT uTbl) +{ + LPCSTR lmem, str; + DWORD flg; + WORD eid; + int idx = 0; + BOOL inCst = FALSE; + + TRACE("Dumping cmdTbl=%d [lpTable=%p devType=%d]\n", + uTbl, S_MciCmdTable[uTbl].lpTable, S_MciCmdTable[uTbl].uDevType); + + if (uTbl >= MAX_MCICMDTABLE || !S_MciCmdTable[uTbl].lpTable) + return FALSE; + + lmem = S_MciCmdTable[uTbl].lpTable; + do { + do { + str = lmem; + lmem += strlen(lmem) + 1; + flg = *(const DWORD*)lmem; + eid = *(const WORD*)(lmem + sizeof(DWORD)); + lmem += sizeof(DWORD) + sizeof(WORD); + idx ++; + /* EPP TRACE("cmd='%s' %08lx %04x\n", str, flg, eid); */ + switch (eid) { + case MCI_COMMAND_HEAD: if (!*str || !flg) return FALSE; idx = 0; break; /* check unicity of str in table */ + case MCI_STRING: if (inCst) return FALSE; break; + case MCI_INTEGER: if (!*str) return FALSE; break; + case MCI_END_COMMAND: if (*str || flg || idx == 0) return FALSE; idx = 0; break; + case MCI_RETURN: if (*str || idx != 1) return FALSE; break; + case MCI_FLAG: if (!*str) return FALSE; break; + case MCI_END_COMMAND_LIST: if (*str || flg) return FALSE; idx = 0; break; + case MCI_RECT: if (!*str || inCst) return FALSE; break; + case MCI_CONSTANT: if (inCst) return FALSE; inCst = TRUE; break; + case MCI_END_CONSTANT: if (*str || flg || !inCst) return FALSE; inCst = FALSE; break; + default: return FALSE; + } + } while (eid != MCI_END_COMMAND_LIST); + } while (eid != MCI_END_COMMAND_LIST); + return TRUE; +} + +/************************************************************************** + * MCI_DumpCommandTable [internal] + */ +static BOOL MCI_DumpCommandTable(UINT uTbl) +{ + LPCSTR lmem; + LPCSTR str; + DWORD flg; + WORD eid; + + if (!MCI_IsCommandTableValid(uTbl)) { + ERR("Ooops: %d is not valid\n", uTbl); + return FALSE; + } + + lmem = S_MciCmdTable[uTbl].lpTable; + do { + do { + str = lmem; + lmem += strlen(lmem) + 1; + flg = *(const DWORD*)lmem; + eid = *(const WORD*)(lmem + sizeof(DWORD)); + TRACE("cmd='%s' %08lx %04x\n", str, flg, eid); + lmem += sizeof(DWORD) + sizeof(WORD); + } while (eid != MCI_END_COMMAND && eid != MCI_END_COMMAND_LIST); + TRACE(" => end of command%s\n", (eid == MCI_END_COMMAND_LIST) ? " list" : ""); + } while (eid != MCI_END_COMMAND_LIST); + return TRUE; +} + + +/************************************************************************** + * MCI_GetCommandTable [internal] + */ +static UINT MCI_GetCommandTable(UINT uDevType) +{ + UINT uTbl; + char buf[32]; + LPCSTR str = NULL; + + /* first look up existing for existing devType */ + for (uTbl = 0; uTbl < MAX_MCICMDTABLE; uTbl++) { + if (S_MciCmdTable[uTbl].lpTable && S_MciCmdTable[uTbl].uDevType == uDevType) + return uTbl; + } + + /* well try to load id */ + if (uDevType >= MCI_DEVTYPE_FIRST && uDevType <= MCI_DEVTYPE_LAST) { + if (LoadStringA(WINMM_IData->hWinMM32Instance, uDevType, buf, sizeof(buf))) { + str = buf; + } + } else if (uDevType == 0) { + str = "CORE"; + } + uTbl = MCI_NO_COMMAND_TABLE; + if (str) { + HRSRC hRsrc = FindResourceA(WINMM_IData->hWinMM32Instance, str, (LPCSTR)RT_RCDATA); + HANDLE hMem = 0; + + if (hRsrc) hMem = LoadResource(WINMM_IData->hWinMM32Instance, hRsrc); + if (hMem) { + uTbl = MCI_SetCommandTable(LockResource(hMem), uDevType); + } else { + WARN("No command table found in resource %p[%s]\n", + WINMM_IData->hWinMM32Instance, str); + } + } + TRACE("=> %d\n", uTbl); + return uTbl; +} + +/************************************************************************** + * MCI_SetCommandTable [internal] + */ +UINT MCI_SetCommandTable(void *table, UINT uDevType) +{ + int uTbl; + static BOOL bInitDone = FALSE; + + /* + * The CORE command table must be loaded first, so that MCI_GetCommandTable() + * can be called with 0 as a uDevType to retrieve it. + * + */ + if (!bInitDone) { + bInitDone = TRUE; + MCI_GetCommandTable(0); + } + + for (uTbl = 0; uTbl < MAX_MCICMDTABLE; uTbl++) { + if (!S_MciCmdTable[uTbl].lpTable) { + LPCSTR lmem, str; + WORD eid; + WORD count; + + S_MciCmdTable[uTbl].uDevType = uDevType; + S_MciCmdTable[uTbl].lpTable = table; + + if (TRACE_ON(mci)) { + MCI_DumpCommandTable(uTbl); + } + + /* create the verbs table */ + /* get # of entries */ + lmem = S_MciCmdTable[uTbl].lpTable; + count = 0; + do { + lmem += strlen(lmem) + 1; + eid = *(const WORD*)(lmem + sizeof(DWORD)); + lmem += sizeof(DWORD) + sizeof(WORD); + if (eid == MCI_COMMAND_HEAD) + count++; + } while (eid != MCI_END_COMMAND_LIST); + + S_MciCmdTable[uTbl].aVerbs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(LPCSTR)); + S_MciCmdTable[uTbl].nVerbs = count; + + lmem = S_MciCmdTable[uTbl].lpTable; + count = 0; + do { + str = lmem; + lmem += strlen(lmem) + 1; + eid = *(const WORD*)(lmem + sizeof(DWORD)); + lmem += sizeof(DWORD) + sizeof(WORD); + if (eid == MCI_COMMAND_HEAD) + S_MciCmdTable[uTbl].aVerbs[count++] = str; + } while (eid != MCI_END_COMMAND_LIST); + /* assert(count == S_MciCmdTable[uTbl].nVerbs); */ + return uTbl; + } + } + + return MCI_NO_COMMAND_TABLE; +} + +/************************************************************************** + * MCI_DeleteCommandTable [internal] + */ +static BOOL MCI_DeleteCommandTable(UINT uTbl) +{ + if (uTbl >= MAX_MCICMDTABLE || !S_MciCmdTable[uTbl].lpTable) + return FALSE; + + S_MciCmdTable[uTbl].lpTable = NULL; + if (S_MciCmdTable[uTbl].aVerbs) { + HeapFree(GetProcessHeap(), 0, S_MciCmdTable[uTbl].aVerbs); + S_MciCmdTable[uTbl].aVerbs = 0; + } + return TRUE; +} + +/************************************************************************** + * MCI_UnLoadMciDriver [internal] + */ +static BOOL MCI_UnLoadMciDriver(LPWINE_MCIDRIVER wmd) +{ + LPWINE_MCIDRIVER* tmp; + + if (!wmd) + return TRUE; + + CloseDriver(wmd->hDriver, 0, 0); + + if (wmd->dwPrivate != 0) + WARN("Unloading mci driver with non nul dwPrivate field\n"); + + EnterCriticalSection(&WINMM_IData->cs); + for (tmp = &WINMM_IData->lpMciDrvs; *tmp; tmp = &(*tmp)->lpNext) { + if (*tmp == wmd) { + *tmp = wmd->lpNext; + break; + } + } + LeaveCriticalSection(&WINMM_IData->cs); + + HeapFree(GetProcessHeap(), 0, wmd->lpstrDeviceType); + HeapFree(GetProcessHeap(), 0, wmd->lpstrAlias); + HeapFree(GetProcessHeap(), 0, wmd->lpstrElementName); + + HeapFree(GetProcessHeap(), 0, wmd); + return TRUE; +} + +/************************************************************************** + * MCI_OpenMciDriver [internal] + */ +static BOOL MCI_OpenMciDriver(LPWINE_MCIDRIVER wmd, LPCSTR drvTyp, LPARAM lp) +{ + char libName[128]; + + if (!DRIVER_GetLibName(drvTyp, "mci", libName, sizeof(libName))) + return FALSE; + + wmd->bIs32 = 0xFFFF; + /* First load driver */ + if ((wmd->hDriver = (HDRVR)DRIVER_TryOpenDriver32(libName, lp))) { + wmd->bIs32 = TRUE; + } else if (WINMM_CheckForMMSystem() && pFnMciMapMsg32ATo16) { + WINMM_MapType res; + + switch (res = pFnMciMapMsg32ATo16(0, DRV_OPEN, 0, &lp)) { + case WINMM_MAP_MSGERROR: + TRACE("Not handled yet (DRV_OPEN)\n"); + break; + case WINMM_MAP_NOMEM: + TRACE("Problem mapping msg=DRV_OPEN from 32a to 16\n"); + break; + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + if ((wmd->hDriver = OpenDriverA(drvTyp, "mci", lp))) + wmd->bIs32 = FALSE; + if (res == WINMM_MAP_OKMEM) + pFnMciUnMapMsg32ATo16(0, DRV_OPEN, 0, lp); + break; + } + } + return (wmd->bIs32 == 0xFFFF) ? FALSE : TRUE; +} + +/************************************************************************** + * MCI_LoadMciDriver [internal] + */ +static DWORD MCI_LoadMciDriver(LPCSTR _strDevTyp, LPWINE_MCIDRIVER* lpwmd) +{ + LPSTR strDevTyp = str_dup_upper(_strDevTyp); + LPWINE_MCIDRIVER wmd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wmd)); + MCI_OPEN_DRIVER_PARMSA modp; + DWORD dwRet = 0; + + if (!wmd || !strDevTyp) { + dwRet = MCIERR_OUT_OF_MEMORY; + goto errCleanUp; + } + + wmd->lpfnYieldProc = MCI_DefYieldProc; + wmd->dwYieldData = VK_CANCEL; + wmd->CreatorThread = GetCurrentThreadId(); + + EnterCriticalSection(&WINMM_IData->cs); + /* wmd must be inserted in list before sending opening the driver, coz' it + * may want to lookup at wDevID + */ + wmd->lpNext = WINMM_IData->lpMciDrvs; + WINMM_IData->lpMciDrvs = wmd; + + for (modp.wDeviceID = MCI_MAGIC; + MCI_GetDriver(modp.wDeviceID) != 0; + modp.wDeviceID++); + + wmd->wDeviceID = modp.wDeviceID; + + LeaveCriticalSection(&WINMM_IData->cs); + + TRACE("wDevID=%04X \n", modp.wDeviceID); + + modp.lpstrParams = NULL; + + if (!MCI_OpenMciDriver(wmd, strDevTyp, (LPARAM)&modp)) { + /* silence warning if all is used... some bogus program use commands like + * 'open all'... + */ + if (strcasecmp(strDevTyp, "all") == 0) { + dwRet = MCIERR_CANNOT_USE_ALL; + } else { + FIXME("Couldn't load driver for type %s.\n" + "If you don't have a windows installation accessible from Wine,\n" + "you perhaps forgot to create a [mci] section in system.ini\n", + strDevTyp); + dwRet = MCIERR_DEVICE_NOT_INSTALLED; + } + goto errCleanUp; + } + + /* FIXME: should also check that module's description is of the form + * MODULENAME:[MCI] comment + */ + + /* some drivers will return 0x0000FFFF, some others 0xFFFFFFFF */ + wmd->uSpecificCmdTable = LOWORD(modp.wCustomCommandTable); + wmd->uTypeCmdTable = MCI_COMMAND_TABLE_NOT_LOADED; + + TRACE("Loaded driver %p (%s), type is %d, cmdTable=%08x\n", + wmd->hDriver, strDevTyp, modp.wType, modp.wCustomCommandTable); + + wmd->lpstrDeviceType = strDevTyp; + wmd->wType = modp.wType; + + TRACE("mcidev=%d, uDevTyp=%04X wDeviceID=%04X !\n", + modp.wDeviceID, modp.wType, modp.wDeviceID); + *lpwmd = wmd; + return 0; +errCleanUp: + MCI_UnLoadMciDriver(wmd); + HeapFree(GetProcessHeap(), 0, strDevTyp); + *lpwmd = 0; + return dwRet; +} + +/************************************************************************** + * MCI_FinishOpen [internal] + */ +static DWORD MCI_FinishOpen(LPWINE_MCIDRIVER wmd, LPMCI_OPEN_PARMSA lpParms, + DWORD dwParam) +{ + if (dwParam & MCI_OPEN_ELEMENT) + { + wmd->lpstrElementName = HeapAlloc(GetProcessHeap(),0,strlen(lpParms->lpstrElementName)+1); + strcpy( wmd->lpstrElementName, lpParms->lpstrElementName ); + } + if (dwParam & MCI_OPEN_ALIAS) + { + wmd->lpstrAlias = HeapAlloc(GetProcessHeap(), 0, strlen(lpParms->lpstrAlias)+1); + strcpy( wmd->lpstrAlias, lpParms->lpstrAlias); + } + lpParms->wDeviceID = wmd->wDeviceID; + + return MCI_SendCommandFrom32(wmd->wDeviceID, MCI_OPEN_DRIVER, dwParam, + (DWORD)lpParms); +} + +/************************************************************************** + * MCI_FindCommand [internal] + */ +static LPCSTR MCI_FindCommand(UINT uTbl, LPCSTR verb) +{ + UINT idx; + + if (uTbl >= MAX_MCICMDTABLE || !S_MciCmdTable[uTbl].lpTable) + return NULL; + + /* another improvement would be to have the aVerbs array sorted, + * so that we could use a dichotomic search on it, rather than this dumb + * array look up + */ + for (idx = 0; idx < S_MciCmdTable[uTbl].nVerbs; idx++) { + if (strcasecmp(S_MciCmdTable[uTbl].aVerbs[idx], verb) == 0) + return S_MciCmdTable[uTbl].aVerbs[idx]; + } + + return NULL; +} + +/************************************************************************** + * MCI_GetReturnType [internal] + */ +static DWORD MCI_GetReturnType(LPCSTR lpCmd) +{ + lpCmd += strlen(lpCmd) + 1 + sizeof(DWORD) + sizeof(WORD); + if (*lpCmd == '\0' && *(const WORD*)(lpCmd + 1 + sizeof(DWORD)) == MCI_RETURN) { + return *(const DWORD*)(lpCmd + 1); + } + return 0L; +} + +/************************************************************************** + * MCI_GetMessage [internal] + */ +static WORD MCI_GetMessage(LPCSTR lpCmd) +{ + return (WORD)*(const DWORD*)(lpCmd + strlen(lpCmd) + 1); +} + +/************************************************************************** + * MCI_GetDWord [internal] + */ +static BOOL MCI_GetDWord(LPDWORD data, LPSTR* ptr) +{ + DWORD val; + LPSTR ret; + + val = strtoul(*ptr, &ret, 0); + + switch (*ret) { + case '\0': break; + case ' ': ret++; break; + default: return FALSE; + } + + *data |= val; + *ptr = ret; + return TRUE; +} + +/************************************************************************** + * MCI_GetString [internal] + */ +static DWORD MCI_GetString(LPSTR* str, LPSTR* args) +{ + LPSTR ptr = *args; + + /* see if we have a quoted string */ + if (*ptr == '"') { + ptr = strchr(*str = ptr + 1, '"'); + if (!ptr) return MCIERR_NO_CLOSING_QUOTE; + /* FIXME: shall we escape \" from string ?? */ + if (ptr[-1] == '\\') TRACE("Ooops: un-escaped \"\n"); + *ptr++ = '\0'; /* remove trailing " */ + if (*ptr != ' ' && *ptr != '\0') return MCIERR_EXTRA_CHARACTERS; + *ptr++ = '\0'; + } else { + ptr = strchr(ptr, ' '); + + if (ptr) { + *ptr++ = '\0'; + } else { + ptr = *args + strlen(*args); + } + *str = *args; + } + + *args = ptr; + return 0; +} + +#define MCI_DATA_SIZE 16 + +/************************************************************************** + * MCI_ParseOptArgs [internal] + */ +static DWORD MCI_ParseOptArgs(LPDWORD data, int _offset, LPCSTR lpCmd, + LPSTR args, LPDWORD dwFlags) +{ + int len, offset; + LPCSTR lmem, str; + DWORD dwRet, flg, cflg = 0; + WORD eid; + BOOL inCst, found; + + /* loop on arguments */ + while (*args) { + lmem = lpCmd; + found = inCst = FALSE; + offset = _offset; + + /* skip any leading white space(s) */ + while (*args == ' ') args++; + TRACE("args='%s' offset=%d\n", args, offset); + + do { /* loop on options for command table for the requested verb */ + str = lmem; + lmem += (len = strlen(lmem)) + 1; + flg = *(const DWORD*)lmem; + eid = *(const WORD*)(lmem + sizeof(DWORD)); + lmem += sizeof(DWORD) + sizeof(WORD); +/* EPP TRACE("\tcmd='%s' inCst=%c eid=%04x\n", str, inCst ? 'Y' : 'N', eid); */ + + switch (eid) { + case MCI_CONSTANT: + inCst = TRUE; cflg = flg; break; + case MCI_END_CONSTANT: + /* there may be additional integral values after flag in constant */ + if (inCst && MCI_GetDWord(&(data[offset]), &args)) { + *dwFlags |= cflg; + } + inCst = FALSE; cflg = 0; + break; + } + + if (strncasecmp(args, str, len) == 0 && + (args[len] == 0 || args[len] == ' ')) { + /* store good values into data[] */ + args += len; + while (*args == ' ') args++; + found = TRUE; + + switch (eid) { + case MCI_COMMAND_HEAD: + case MCI_RETURN: + case MCI_END_COMMAND: + case MCI_END_COMMAND_LIST: + case MCI_CONSTANT: /* done above */ + case MCI_END_CONSTANT: /* done above */ + break; + case MCI_FLAG: + *dwFlags |= flg; + break; + case MCI_INTEGER: + if (inCst) { + data[offset] |= flg; + *dwFlags |= cflg; + inCst = FALSE; + } else { + *dwFlags |= flg; + if (!MCI_GetDWord(&(data[offset]), &args)) { + return MCIERR_BAD_INTEGER; + } + } + break; + case MCI_RECT: + /* store rect in data (offset...offset+3) */ + *dwFlags |= flg; + if (!MCI_GetDWord(&(data[offset+0]), &args) || + !MCI_GetDWord(&(data[offset+1]), &args) || + !MCI_GetDWord(&(data[offset+2]), &args) || + !MCI_GetDWord(&(data[offset+3]), &args)) { + ERR("Bad rect '%s'\n", args); + return MCIERR_BAD_INTEGER; + } + break; + case MCI_STRING: + *dwFlags |= flg; + if ((dwRet = MCI_GetString((LPSTR*)&data[offset], &args))) + return dwRet; + break; + default: ERR("oops\n"); + } + /* exit inside while loop, except if just entered in constant area definition */ + if (!inCst || eid != MCI_CONSTANT) eid = MCI_END_COMMAND; + } else { + /* have offset incremented if needed */ + switch (eid) { + case MCI_COMMAND_HEAD: + case MCI_RETURN: + case MCI_END_COMMAND: + case MCI_END_COMMAND_LIST: + case MCI_CONSTANT: + case MCI_FLAG: break; + case MCI_INTEGER: if (!inCst) offset++; break; + case MCI_END_CONSTANT: + case MCI_STRING: offset++; break; + case MCI_RECT: offset += 4; break; + default: ERR("oops\n"); + } + } + } while (eid != MCI_END_COMMAND); + if (!found) { + WARN("Optarg '%s' not found\n", args); + return MCIERR_UNRECOGNIZED_COMMAND; + } + if (offset == MCI_DATA_SIZE) { + ERR("Internal data[] buffer overflow\n"); + return MCIERR_PARSER_INTERNAL; + } + } + return 0; +} + +/************************************************************************** + * MCI_HandleReturnValues [internal] + */ +static DWORD MCI_HandleReturnValues(DWORD dwRet, LPWINE_MCIDRIVER wmd, DWORD retType, + LPDWORD data, LPSTR lpstrRet, UINT uRetLen) +{ + if (lpstrRet) { + switch (retType) { + case 0: /* nothing to return */ + break; + case MCI_INTEGER: + switch (dwRet & 0xFFFF0000ul) { + case 0: + case MCI_INTEGER_RETURNED: + snprintf(lpstrRet, uRetLen, "%ld", data[1]); + break; + case MCI_RESOURCE_RETURNED: + /* return string which ID is HIWORD(data[1]), + * string is loaded from mmsystem.dll */ + LoadStringA(WINMM_IData->hWinMM32Instance, HIWORD(data[1]), + lpstrRet, uRetLen); + break; + case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER: + /* return string which ID is HIWORD(data[1]), + * string is loaded from driver */ + /* FIXME: this is wrong for a 16 bit handle */ + LoadStringA(GetDriverModuleHandle(wmd->hDriver), + HIWORD(data[1]), lpstrRet, uRetLen); + break; + case MCI_COLONIZED3_RETURN: + snprintf(lpstrRet, uRetLen, "%d:%d:%d", + LOBYTE(LOWORD(data[1])), HIBYTE(LOWORD(data[1])), + LOBYTE(HIWORD(data[1]))); + break; + case MCI_COLONIZED4_RETURN: + snprintf(lpstrRet, uRetLen, "%d:%d:%d:%d", + LOBYTE(LOWORD(data[1])), HIBYTE(LOWORD(data[1])), + LOBYTE(HIWORD(data[1])), HIBYTE(HIWORD(data[1]))); + break; + default: ERR("Ooops (%04X)\n", HIWORD(dwRet)); + } + break; + case MCI_STRING: + switch (dwRet & 0xFFFF0000ul) { + case 0: + /* nothing to do data[1] == lpstrRet */ + break; + case MCI_INTEGER_RETURNED: + data[1] = *(LPDWORD)lpstrRet; + snprintf(lpstrRet, uRetLen, "%ld", data[1]); + break; + default: + WARN("Oooch. MCI_STRING and HIWORD(dwRet)=%04x\n", HIWORD(dwRet)); + break; + } + break; + case MCI_RECT: + if (dwRet & 0xFFFF0000ul) + WARN("Oooch. MCI_STRING and HIWORD(dwRet)=%04x\n", HIWORD(dwRet)); + snprintf(lpstrRet, uRetLen, "%ld %ld %ld %ld", + data[1], data[2], data[3], data[4]); + break; + default: ERR("oops\n"); + } + } + return LOWORD(dwRet); +} + +/************************************************************************** + * mciSendStringA [WINMM.@] + */ +DWORD WINAPI mciSendStringA(LPCSTR lpstrCommand, LPSTR lpstrRet, + UINT uRetLen, HWND hwndCallback) +{ + LPSTR verb, dev, args; + LPWINE_MCIDRIVER wmd = 0; + DWORD dwFlags = 0, dwRet = 0; + int offset = 0; + DWORD data[MCI_DATA_SIZE]; + DWORD retType; + LPCSTR lpCmd = 0; + LPSTR devAlias = NULL; + BOOL bAutoOpen = FALSE; + + TRACE("('%s', %p, %d, %p)\n", lpstrCommand, lpstrRet, uRetLen, hwndCallback); + + /* format is */ + if (!(verb = HeapAlloc(GetProcessHeap(), 0, strlen(lpstrCommand)+1))) + return MCIERR_OUT_OF_MEMORY; + strcpy( verb, lpstrCommand ); + CharLowerA(verb); + + memset(data, 0, sizeof(data)); + + if (!(args = strchr(verb, ' '))) { + dwRet = MCIERR_MISSING_DEVICE_NAME; + goto errCleanUp; + } + *args++ = '\0'; + if ((dwRet = MCI_GetString(&dev, &args))) { + goto errCleanUp; + } + + /* case dev == 'new' has to be handled */ + if (!strcmp(dev, "new")) { + FIXME("'new': NIY as device name\n"); + dwRet = MCIERR_MISSING_DEVICE_NAME; + goto errCleanUp; + } + + /* otherwise, try to grab devType from open */ + if (!strcmp(verb, "open")) { + LPSTR devType, tmp; + + if ((devType = strchr(dev, '!')) != NULL) { + *devType++ = '\0'; + tmp = devType; devType = dev; dev = tmp; + + dwFlags |= MCI_OPEN_TYPE; + data[2] = (DWORD)devType; + devType = str_dup_upper(devType); + dwFlags |= MCI_OPEN_ELEMENT; + data[3] = (DWORD)dev; + } else if (strchr(dev, '.') == NULL) { + tmp = strchr(dev,' '); + if (tmp) *tmp = '\0'; + data[2] = (DWORD)dev; + devType = str_dup_upper(dev); + if (tmp) *tmp = ' '; + dwFlags |= MCI_OPEN_TYPE; + } else { + if ((devType = strstr(args, "type ")) != NULL) { + devType += 5; + tmp = strchr(devType, ' '); + if (tmp) *tmp = '\0'; + devType = str_dup_upper(devType); + if (tmp) *tmp = ' '; + /* dwFlags and data[2] will be correctly set in ParseOpt loop */ + } else { + char buf[32]; + if ((dwRet = MCI_GetDevTypeFromFileName(dev, buf, sizeof(buf)))) + goto errCleanUp; + + devType = str_dup_upper(buf); + } + dwFlags |= MCI_OPEN_ELEMENT; + data[3] = (DWORD)dev; + } + if ((devAlias = strstr(args," alias "))) { + char *tmp2; + devAlias += 7; + if (!(tmp = strchr(devAlias,' '))) tmp = devAlias + strlen(devAlias); + if (tmp) *tmp = '\0'; + tmp2 = HeapAlloc(GetProcessHeap(), 0, tmp - devAlias + 1 ); + memcpy( tmp2, devAlias, tmp - devAlias ); + tmp2[tmp - devAlias] = 0; + data[4] = (DWORD)tmp2; + /* should be done in regular options parsing */ + /* dwFlags |= MCI_OPEN_ALIAS; */ + } + + dwRet = MCI_LoadMciDriver(devType, &wmd); + if (dwRet == MCIERR_DEVICE_NOT_INSTALLED) + dwRet = MCIERR_INVALID_DEVICE_NAME; + HeapFree(GetProcessHeap(), 0, devType); + if (dwRet) { + MCI_UnLoadMciDriver(wmd); + goto errCleanUp; + } + } else if (!(wmd = MCI_GetDriver(mciGetDeviceIDA(dev)))) { + /* auto open */ + char buf[128]; + sprintf(buf, "open %s wait", dev); + + if ((dwRet = mciSendStringA(buf, NULL, 0, 0)) != 0) + goto errCleanUp; + + wmd = MCI_GetDriver(mciGetDeviceIDA(dev)); + if (!wmd) { + /* FIXME: memory leak, MCI driver is not closed */ + dwRet = MCIERR_INVALID_DEVICE_ID; + goto errCleanUp; + } + } + + /* get the verb in the different command tables */ + if (wmd) { + /* try the device specific command table */ + lpCmd = MCI_FindCommand(wmd->uSpecificCmdTable, verb); + if (!lpCmd) { + /* try the type specific command table */ + if (wmd->uTypeCmdTable == MCI_COMMAND_TABLE_NOT_LOADED) + wmd->uTypeCmdTable = MCI_GetCommandTable(wmd->wType); + if (wmd->uTypeCmdTable != MCI_NO_COMMAND_TABLE) + lpCmd = MCI_FindCommand(wmd->uTypeCmdTable, verb); + } + } + /* try core command table */ + if (!lpCmd) lpCmd = MCI_FindCommand(MCI_GetCommandTable(0), verb); + + if (!lpCmd) { + TRACE("Command '%s' not found!\n", verb); + dwRet = MCIERR_UNRECOGNIZED_COMMAND; + goto errCleanUp; + } + + /* set up call back */ + if (hwndCallback != 0) { + dwFlags |= MCI_NOTIFY; + data[0] = (DWORD)hwndCallback; + } + + /* set return information */ + switch (retType = MCI_GetReturnType(lpCmd)) { + case 0: offset = 1; break; + case MCI_INTEGER: offset = 2; break; + case MCI_STRING: data[1] = (DWORD)lpstrRet; data[2] = uRetLen; offset = 3; break; + case MCI_RECT: offset = 5; break; + default: ERR("oops\n"); + } + + TRACE("verb='%s' on dev='%s'; offset=%d\n", verb, dev, offset); + + if ((dwRet = MCI_ParseOptArgs(data, offset, lpCmd, args, &dwFlags))) + goto errCleanUp; + + if (bAutoOpen && (dwFlags & MCI_NOTIFY)) { + dwRet = MCIERR_NOTIFY_ON_AUTO_OPEN; + goto errCleanUp; + } + /* FIXME: the command should get it's own notification window set up and + * ask for device closing while processing the notification mechanism + */ + if (lpstrRet && uRetLen) *lpstrRet = '\0'; + + TRACE("[%d, %s, %08lx, %08lx/%s %08lx/%s %08lx/%s %08lx/%s %08lx/%s %08lx/%s]\n", + wmd->wDeviceID, MCI_MessageToString(MCI_GetMessage(lpCmd)), dwFlags, + data[0], debugstr_a((char *)data[0]), data[1], debugstr_a((char *)data[1]), + data[2], debugstr_a((char *)data[2]), data[3], debugstr_a((char *)data[3]), + data[4], debugstr_a((char *)data[4]), data[5], debugstr_a((char *)data[5])); + + if (strcmp(verb, "open") == 0) { + if ((dwRet = MCI_FinishOpen(wmd, (LPMCI_OPEN_PARMSA)data, dwFlags))) + MCI_UnLoadMciDriver(wmd); + /* FIXME: notification is not properly shared across two opens */ + } else { + dwRet = MCI_SendCommand(wmd->wDeviceID, MCI_GetMessage(lpCmd), dwFlags, (DWORD)data, TRUE); + } + TRACE("=> 1/ %lx (%s)\n", dwRet, lpstrRet); + dwRet = MCI_HandleReturnValues(dwRet, wmd, retType, data, lpstrRet, uRetLen); + TRACE("=> 2/ %lx (%s)\n", dwRet, lpstrRet); + +errCleanUp: + HeapFree(GetProcessHeap(), 0, verb); + HeapFree(GetProcessHeap(), 0, devAlias); + return dwRet; +} + +/************************************************************************** + * mciSendStringW [WINMM.@] + */ +DWORD WINAPI mciSendStringW(LPCWSTR lpwstrCommand, LPWSTR lpwstrRet, + UINT uRetLen, HWND hwndCallback) +{ + LPSTR lpstrCommand; + LPSTR lpstrRet = NULL; + UINT ret; + INT len; + + /* FIXME: is there something to do with lpstrReturnString ? */ + len = WideCharToMultiByte( CP_ACP, 0, lpwstrCommand, -1, NULL, 0, NULL, NULL ); + lpstrCommand = HeapAlloc( GetProcessHeap(), 0, len ); + WideCharToMultiByte( CP_ACP, 0, lpwstrCommand, -1, lpstrCommand, len, NULL, NULL ); + if (lpwstrRet) + { + lpstrRet = HeapAlloc(GetProcessHeap(), 0, uRetLen * sizeof(WCHAR)); + if (!lpstrRet) return MMSYSERR_NOMEM; + } + ret = mciSendStringA(lpstrCommand, lpstrRet, uRetLen, hwndCallback); + if (lpwstrRet) + MultiByteToWideChar( CP_ACP, 0, lpstrRet, -1, lpwstrRet, uRetLen ); + HeapFree(GetProcessHeap(), 0, lpstrCommand); + if (lpstrRet) HeapFree(GetProcessHeap(), 0, lpstrRet); + return ret; +} + +/************************************************************************** + * mciExecute [WINMM.@] + * mciExecute [MMSYSTEM.712] + */ +DWORD WINAPI mciExecute(LPCSTR lpstrCommand) +{ + char strRet[256]; + DWORD ret; + + TRACE("(%s)!\n", lpstrCommand); + + ret = mciSendStringA(lpstrCommand, strRet, sizeof(strRet), 0); + if (ret != 0) { + if (!mciGetErrorStringA(ret, strRet, sizeof(strRet))) { + sprintf(strRet, "Unknown MCI error (%ld)", ret); + } + MessageBoxA(0, strRet, "Error in mciExecute()", MB_OK); + } + /* FIXME: what shall I return ? */ + return 0; +} + +/************************************************************************** + * mciLoadCommandResource [WINMM.@] + * + * Strangely, this function only exists as an UNICODE one. + */ +UINT WINAPI mciLoadCommandResource(HINSTANCE hInst, LPCWSTR resNameW, UINT type) +{ + HRSRC hRsrc = 0; + HGLOBAL hMem; + UINT16 ret = MCI_NO_COMMAND_TABLE; + + TRACE("(%p, %s, %d)!\n", hInst, debugstr_w(resNameW), type); + + /* if a file named "resname.mci" exits, then load resource "resname" from it + * otherwise directly from driver + * We don't support it (who uses this feature ?), but we check anyway + */ + if (!type) { +#if 0 + /* FIXME: we should put this back into order, but I never found a program + * actually using this feature, so we not need it + */ + char buf[128]; + OFSTRUCT ofs; + + strcat(strcpy(buf, resname), ".mci"); + if (OpenFile(buf, &ofs, OF_EXIST) != HFILE_ERROR) { + FIXME("NIY: command table to be loaded from '%s'\n", ofs.szPathName); + } +#endif + } + if (!(hRsrc = FindResourceW(hInst, resNameW, (LPWSTR)RT_RCDATA))) { + WARN("No command table found in resource\n"); + } else if ((hMem = LoadResource(hInst, hRsrc))) { + ret = MCI_SetCommandTable(LockResource(hMem), type); + } else { + WARN("Couldn't load resource.\n"); + } + TRACE("=> %04x\n", ret); + return ret; +} + +/************************************************************************** + * mciFreeCommandResource [WINMM.@] + */ +BOOL WINAPI mciFreeCommandResource(UINT uTable) +{ + TRACE("(%08x)!\n", uTable); + + return MCI_DeleteCommandTable(uTable); +} + +/************************************************************************** + * MCI_SendCommandFrom32 [internal] + */ +DWORD MCI_SendCommandFrom32(MCIDEVICEID wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + DWORD dwRet = MCIERR_INVALID_DEVICE_ID; + LPWINE_MCIDRIVER wmd = MCI_GetDriver(wDevID); + + if (wmd) { + if (wmd->bIs32) { + dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2); + } else if (pFnMciMapMsg32ATo16) { + WINMM_MapType res; + + switch (res = pFnMciMapMsg32ATo16(wmd->wType, wMsg, dwParam1, &dwParam2)) { + case WINMM_MAP_MSGERROR: + TRACE("Not handled yet (%s)\n", MCI_MessageToString(wMsg)); + dwRet = MCIERR_DRIVER_INTERNAL; + break; + case WINMM_MAP_NOMEM: + TRACE("Problem mapping msg=%s from 32a to 16\n", MCI_MessageToString(wMsg)); + dwRet = MCIERR_OUT_OF_MEMORY; + break; + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2); + if (res == WINMM_MAP_OKMEM) + pFnMciUnMapMsg32ATo16(wmd->wType, wMsg, dwParam1, dwParam2); + break; + } + } + } + return dwRet; +} + +/************************************************************************** + * MCI_SendCommandFrom16 [internal] + */ +DWORD MCI_SendCommandFrom16(MCIDEVICEID wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + DWORD dwRet = MCIERR_INVALID_DEVICE_ID; + LPWINE_MCIDRIVER wmd = MCI_GetDriver(wDevID); + + if (wmd) { + dwRet = MCIERR_INVALID_DEVICE_ID; + + if (wmd->bIs32 && pFnMciMapMsg16To32A) { + WINMM_MapType res; + + switch (res = pFnMciMapMsg16To32A(wmd->wType, wMsg, &dwParam2)) { + case WINMM_MAP_MSGERROR: + TRACE("Not handled yet (%s)\n", MCI_MessageToString(wMsg)); + dwRet = MCIERR_DRIVER_INTERNAL; + break; + case WINMM_MAP_NOMEM: + TRACE("Problem mapping msg=%s from 16 to 32a\n", MCI_MessageToString(wMsg)); + dwRet = MCIERR_OUT_OF_MEMORY; + break; + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2); + if (res == WINMM_MAP_OKMEM) + pFnMciUnMapMsg16To32A(wmd->wType, wMsg, dwParam2); + break; + } + } else { + dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2); + } + } + return dwRet; +} + +/************************************************************************** + * MCI_Open [internal] + */ +static DWORD MCI_Open(DWORD dwParam, LPMCI_OPEN_PARMSA lpParms) +{ + char strDevTyp[128]; + DWORD dwRet; + LPWINE_MCIDRIVER wmd = NULL; + + TRACE("(%08lX, %p)\n", dwParam, lpParms); + if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK; + + /* only two low bytes are generic, the other ones are dev type specific */ +#define WINE_MCIDRIVER_SUPP (0xFFFF0000|MCI_OPEN_SHAREABLE|MCI_OPEN_ELEMENT| \ + MCI_OPEN_ALIAS|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID| \ + MCI_NOTIFY|MCI_WAIT) + if ((dwParam & ~WINE_MCIDRIVER_SUPP) != 0) { + FIXME("Unsupported yet dwFlags=%08lX\n", dwParam & ~WINE_MCIDRIVER_SUPP); + } +#undef WINE_MCIDRIVER_SUPP + + strDevTyp[0] = 0; + + if (dwParam & MCI_OPEN_TYPE) { + if (dwParam & MCI_OPEN_TYPE_ID) { + WORD uDevType = LOWORD((DWORD)lpParms->lpstrDeviceType); + + if (uDevType < MCI_DEVTYPE_FIRST || + uDevType > MCI_DEVTYPE_LAST || + !LoadStringA(WINMM_IData->hWinMM32Instance, uDevType, strDevTyp, sizeof(strDevTyp))) { + dwRet = MCIERR_BAD_INTEGER; + goto errCleanUp; + } + } else { + LPSTR ptr; + if (lpParms->lpstrDeviceType == NULL) { + dwRet = MCIERR_NULL_PARAMETER_BLOCK; + goto errCleanUp; + } + strcpy(strDevTyp, lpParms->lpstrDeviceType); + ptr = strchr(strDevTyp, '!'); + if (ptr) { + /* this behavior is not documented in windows. However, since, in + * some occasions, MCI_OPEN handling is translated by WinMM into + * a call to mciSendString("open "); this code shall be correct + */ + if (dwParam & MCI_OPEN_ELEMENT) { + ERR("Both MCI_OPEN_ELEMENT(%s) and %s are used\n", + lpParms->lpstrElementName, strDevTyp); + dwRet = MCIERR_UNRECOGNIZED_KEYWORD; + goto errCleanUp; + } + dwParam |= MCI_OPEN_ELEMENT; + *ptr++ = 0; + /* FIXME: not a good idea to write in user supplied buffer */ + lpParms->lpstrElementName = ptr; + } + + } + TRACE("devType='%s' !\n", strDevTyp); + } + + if (dwParam & MCI_OPEN_ELEMENT) { + TRACE("lpstrElementName='%s'\n", lpParms->lpstrElementName); + + if (dwParam & MCI_OPEN_ELEMENT_ID) { + FIXME("Unsupported yet flag MCI_OPEN_ELEMENT_ID\n"); + dwRet = MCIERR_UNRECOGNIZED_KEYWORD; + goto errCleanUp; + } + + if (!lpParms->lpstrElementName) { + dwRet = MCIERR_NULL_PARAMETER_BLOCK; + goto errCleanUp; + } + + /* type, if given as a parameter, supersedes file extension */ + if (!strDevTyp[0] && + MCI_GetDevTypeFromFileName(lpParms->lpstrElementName, + strDevTyp, sizeof(strDevTyp))) { + if (GetDriveTypeA(lpParms->lpstrElementName) != DRIVE_CDROM) { + dwRet = MCIERR_EXTENSION_NOT_FOUND; + goto errCleanUp; + } + /* FIXME: this will not work if several CDROM drives are installed on the machine */ + strcpy(strDevTyp, "CDAUDIO"); + } + } + + if (strDevTyp[0] == 0) { + FIXME("Couldn't load driver\n"); + dwRet = MCIERR_INVALID_DEVICE_NAME; + goto errCleanUp; + } + + if (dwParam & MCI_OPEN_ALIAS) { + TRACE("Alias='%s' !\n", lpParms->lpstrAlias); + if (!lpParms->lpstrAlias) { + dwRet = MCIERR_NULL_PARAMETER_BLOCK; + goto errCleanUp; + } + } + + if ((dwRet = MCI_LoadMciDriver(strDevTyp, &wmd))) { + goto errCleanUp; + } + + if ((dwRet = MCI_FinishOpen(wmd, lpParms, dwParam))) { + TRACE("Failed to open driver (MCI_OPEN_DRIVER) [%08lx], closing\n", dwRet); + /* FIXME: is dwRet the correct ret code ? */ + goto errCleanUp; + } + + /* only handled devices fall through */ + TRACE("wDevID=%04X wDeviceID=%d dwRet=%ld\n", wmd->wDeviceID, lpParms->wDeviceID, dwRet); + + if (dwParam & MCI_NOTIFY) + mciDriverNotify((HWND)lpParms->dwCallback, wmd->wDeviceID, MCI_NOTIFY_SUCCESSFUL); + + return 0; +errCleanUp: + if (wmd) MCI_UnLoadMciDriver(wmd); + + if (dwParam & MCI_NOTIFY) + mciDriverNotify((HWND)lpParms->dwCallback, 0, MCI_NOTIFY_FAILURE); + return dwRet; +} + +/************************************************************************** + * MCI_Close [internal] + */ +static DWORD MCI_Close(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms) +{ + DWORD dwRet; + LPWINE_MCIDRIVER wmd; + + TRACE("(%04x, %08lX, %p)\n", wDevID, dwParam, lpParms); + + if (wDevID == MCI_ALL_DEVICE_ID) { + LPWINE_MCIDRIVER next; + + EnterCriticalSection(&WINMM_IData->cs); + /* FIXME: shall I notify once after all is done, or for + * each of the open drivers ? if the latest, which notif + * to return when only one fails ? + */ + for (wmd = WINMM_IData->lpMciDrvs; wmd; ) { + next = wmd->lpNext; + MCI_Close(wmd->wDeviceID, dwParam, lpParms); + wmd = next; + } + LeaveCriticalSection(&WINMM_IData->cs); + return 0; + } + + if (!(wmd = MCI_GetDriver(wDevID))) { + return MCIERR_INVALID_DEVICE_ID; + } + + dwRet = MCI_SendCommandFrom32(wDevID, MCI_CLOSE_DRIVER, dwParam, (DWORD)lpParms); + + MCI_UnLoadMciDriver(wmd); + + if (dwParam & MCI_NOTIFY) + mciDriverNotify((HWND)lpParms->dwCallback, wDevID, + (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE); + + return dwRet; +} + +/************************************************************************** + * MCI_WriteString [internal] + */ +DWORD MCI_WriteString(LPSTR lpDstStr, DWORD dstSize, LPCSTR lpSrcStr) +{ + DWORD ret = 0; + + if (lpSrcStr) { + if (dstSize <= strlen(lpSrcStr)) { + lstrcpynA(lpDstStr, lpSrcStr, dstSize - 1); + ret = MCIERR_PARAM_OVERFLOW; + } else { + strcpy(lpDstStr, lpSrcStr); + } + } else { + *lpDstStr = 0; + } + return ret; +} + +/************************************************************************** + * MCI_Sysinfo [internal] + */ +static DWORD MCI_SysInfo(UINT uDevID, DWORD dwFlags, LPMCI_SYSINFO_PARMSA lpParms) +{ + DWORD ret = MCIERR_INVALID_DEVICE_ID, cnt = 0; + CHAR buf[2048], *s = buf, *p; + LPWINE_MCIDRIVER wmd; + HKEY hKey; + + if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK; + + TRACE("(%08x, %08lX, %08lX[num=%ld, wDevTyp=%u])\n", + uDevID, dwFlags, (DWORD)lpParms, lpParms->dwNumber, lpParms->wDeviceType); + + switch (dwFlags & ~MCI_SYSINFO_OPEN) { + case MCI_SYSINFO_QUANTITY: + if (lpParms->wDeviceType < MCI_DEVTYPE_FIRST || lpParms->wDeviceType > MCI_DEVTYPE_LAST) { + if (dwFlags & MCI_SYSINFO_OPEN) { + TRACE("MCI_SYSINFO_QUANTITY: # of open MCI drivers\n"); + EnterCriticalSection(&WINMM_IData->cs); + for (wmd = WINMM_IData->lpMciDrvs; wmd; wmd = wmd->lpNext) { + cnt++; + } + LeaveCriticalSection(&WINMM_IData->cs); + } else { + TRACE("MCI_SYSINFO_QUANTITY: # of installed MCI drivers\n"); + if (RegOpenKeyExA( HKEY_LOCAL_MACHINE, HKLM_MCI, + 0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) { + RegQueryInfoKeyA( hKey, 0, 0, 0, &cnt, 0, 0, 0, 0, 0, 0, 0); + RegCloseKey( hKey ); + } + if (GetPrivateProfileStringA("mci", 0, "", buf, sizeof(buf), "system.ini")) + for(s = buf; *s; s += strlen(s) + 1) cnt++; + } + } else { + if (dwFlags & MCI_SYSINFO_OPEN) { + TRACE("MCI_SYSINFO_QUANTITY: # of open MCI drivers of type %u\n", lpParms->wDeviceType); + EnterCriticalSection(&WINMM_IData->cs); + for (wmd = WINMM_IData->lpMciDrvs; wmd; wmd = wmd->lpNext) { + if (wmd->wType == lpParms->wDeviceType) cnt++; + } + LeaveCriticalSection(&WINMM_IData->cs); + } else { + TRACE("MCI_SYSINFO_QUANTITY: # of installed MCI drivers of type %u\n", lpParms->wDeviceType); + FIXME("Don't know how to get # of MCI devices of a given type\n"); + cnt = 1; + } + } + *(DWORD*)lpParms->lpstrReturn = cnt; + TRACE("(%ld) => '%ld'\n", lpParms->dwNumber, *(DWORD*)lpParms->lpstrReturn); + ret = MCI_INTEGER_RETURNED; + break; + case MCI_SYSINFO_INSTALLNAME: + TRACE("MCI_SYSINFO_INSTALLNAME \n"); + if ((wmd = MCI_GetDriver(uDevID))) { + ret = MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, + wmd->lpstrDeviceType); + } else { + *lpParms->lpstrReturn = 0; + ret = MCIERR_INVALID_DEVICE_ID; + } + TRACE("(%ld) => '%s'\n", lpParms->dwNumber, lpParms->lpstrReturn); + break; + case MCI_SYSINFO_NAME: + TRACE("MCI_SYSINFO_NAME\n"); + if (dwFlags & MCI_SYSINFO_OPEN) { + FIXME("Don't handle MCI_SYSINFO_NAME|MCI_SYSINFO_OPEN (yet)\n"); + ret = MCIERR_UNRECOGNIZED_COMMAND; + } else { + DWORD lRet; + s = 0; + lRet = RegOpenKeyExA( HKEY_LOCAL_MACHINE, HKLM_MCI, 0, KEY_QUERY_VALUE, &hKey ); + if (lRet == ERROR_SUCCESS) { + lRet = RegQueryInfoKeyA( hKey, 0, 0, 0, &cnt, 0, 0, 0, 0, 0, 0, 0); + if (lRet == ERROR_SUCCESS && lpParms->dwNumber <= cnt) { + DWORD bufLen = sizeof(buf); + lRet = RegEnumKeyExA(hKey, lpParms->dwNumber - 1, buf, &bufLen, 0, 0, 0, 0); + if (lRet == ERROR_SUCCESS) s = buf; + } + RegCloseKey( hKey ); + } + if (!s) { + if (GetPrivateProfileStringA("mci", 0, "", buf, sizeof(buf), "system.ini")) { + for(p = buf; *p; p += strlen(p) + 1, cnt++) { + TRACE("%ld: %s\n", cnt, p); + if (cnt == lpParms->dwNumber - 1) { + s = p; + break; + } + } + } + } + ret = s ? MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, s) : MCIERR_OUTOFRANGE; + } + TRACE("(%ld) => '%s'\n", lpParms->dwNumber, lpParms->lpstrReturn); + break; + default: + TRACE("Unsupported flag value=%08lx\n", dwFlags); + ret = MCIERR_UNRECOGNIZED_COMMAND; + } + return ret; +} + +/************************************************************************** + * MCI_Break [internal] + */ +static DWORD MCI_Break(UINT wDevID, DWORD dwFlags, LPMCI_BREAK_PARMS lpParms) +{ + DWORD dwRet = 0; + + if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK; + + if (dwFlags & MCI_NOTIFY) + mciDriverNotify((HWND)lpParms->dwCallback, wDevID, + (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE); + + return dwRet; +} + +/************************************************************************** + * MCI_Sound [internal] + */ +static DWORD MCI_Sound(UINT wDevID, DWORD dwFlags, LPMCI_SOUND_PARMS lpParms) +{ + DWORD dwRet = 0; + + if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK; + + if (dwFlags & MCI_SOUND_NAME) + dwRet = sndPlaySoundA(lpParms->lpstrSoundName, SND_SYNC) ? MMSYSERR_NOERROR : MMSYSERR_ERROR; + else + dwRet = MMSYSERR_ERROR; /* what should be done ??? */ + if (dwFlags & MCI_NOTIFY) + mciDriverNotify((HWND)lpParms->dwCallback, wDevID, + (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE); + + return dwRet; +} + +/************************************************************************** + * MCI_SendCommand [internal] + */ +DWORD MCI_SendCommand(UINT wDevID, UINT16 wMsg, DWORD dwParam1, + DWORD dwParam2, BOOL bFrom32) +{ + DWORD dwRet = MCIERR_UNRECOGNIZED_COMMAND; + + switch (wMsg) { + case MCI_OPEN: + if (bFrom32) { + dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2); + } else if (pFnMciMapMsg16To32A) { + switch (pFnMciMapMsg16To32A(0, wMsg, &dwParam2)) { + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2); + pFnMciUnMapMsg16To32A(0, wMsg, dwParam2); + break; + default: break; /* so that gcc does not bark */ + } + } + break; + case MCI_CLOSE: + if (bFrom32) { + dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2); + } else if (pFnMciMapMsg16To32A) { + switch (pFnMciMapMsg16To32A(0, wMsg, &dwParam2)) { + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2); + pFnMciUnMapMsg16To32A(0, wMsg, dwParam2); + break; + default: break; /* so that gcc does not bark */ + } + } + break; + case MCI_SYSINFO: + if (bFrom32) { + dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2); + } else if (pFnMciMapMsg16To32A) { + switch (pFnMciMapMsg16To32A(0, wMsg, &dwParam2)) { + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2); + pFnMciUnMapMsg16To32A(0, wMsg, dwParam2); + break; + default: break; /* so that gcc does not bark */ + } + } + break; + case MCI_BREAK: + if (bFrom32) { + dwRet = MCI_Break(wDevID, dwParam1, (LPMCI_BREAK_PARMS)dwParam2); + } else if (pFnMciMapMsg16To32A) { + switch (pFnMciMapMsg16To32A(0, wMsg, &dwParam2)) { + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + dwRet = MCI_Break(wDevID, dwParam1, (LPMCI_BREAK_PARMS)dwParam2); + pFnMciUnMapMsg16To32A(0, wMsg, dwParam2); + break; + default: break; /* so that gcc does not bark */ + } + } + break; + case MCI_SOUND: + if (bFrom32) { + dwRet = MCI_Sound(wDevID, dwParam1, (LPMCI_SOUND_PARMS)dwParam2); + } else if (pFnMciMapMsg16To32A) { + switch (pFnMciMapMsg16To32A(0, wMsg, &dwParam2)) { + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + dwRet = MCI_Sound(wDevID, dwParam1, (LPMCI_SOUND_PARMS)dwParam2); + pFnMciUnMapMsg16To32A(0, wMsg, dwParam2); + break; + default: break; /* so that gcc does not bark */ + } + } + break; + default: + if (wDevID == MCI_ALL_DEVICE_ID) { + FIXME("unhandled MCI_ALL_DEVICE_ID\n"); + dwRet = MCIERR_CANNOT_USE_ALL; + } else { + dwRet = (bFrom32) ? + MCI_SendCommandFrom32(wDevID, wMsg, dwParam1, dwParam2) : + MCI_SendCommandFrom16(wDevID, wMsg, dwParam1, dwParam2); + } + break; + } + return dwRet; +} + +/************************************************************************** + * MCI_CleanUp [internal] + * + * Some MCI commands need to be cleaned-up (when not called from + * mciSendString), because MCI drivers return extra information for string + * transformation. This function gets rid of them. + */ +LRESULT MCI_CleanUp(LRESULT dwRet, UINT wMsg, DWORD dwParam2) +{ + if (LOWORD(dwRet)) + return LOWORD(dwRet); + + switch (wMsg) { + case MCI_GETDEVCAPS: + switch (dwRet & 0xFFFF0000ul) { + case 0: + case MCI_COLONIZED3_RETURN: + case MCI_COLONIZED4_RETURN: + case MCI_INTEGER_RETURNED: + /* nothing to do */ + break; + case MCI_RESOURCE_RETURNED: + case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER: + { + LPMCI_GETDEVCAPS_PARMS lmgp; + + lmgp = (LPMCI_GETDEVCAPS_PARMS)(void*)dwParam2; + TRACE("Changing %08lx to %08lx\n", lmgp->dwReturn, (DWORD)LOWORD(lmgp->dwReturn)); + lmgp->dwReturn = LOWORD(lmgp->dwReturn); + } + break; + default: + FIXME("Unsupported value for hiword (%04x) returned by DriverProc(%s)\n", + HIWORD(dwRet), MCI_MessageToString(wMsg)); + } + break; + case MCI_STATUS: + switch (dwRet & 0xFFFF0000ul) { + case 0: + case MCI_COLONIZED3_RETURN: + case MCI_COLONIZED4_RETURN: + case MCI_INTEGER_RETURNED: + /* nothing to do */ + break; + case MCI_RESOURCE_RETURNED: + case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER: + { + LPMCI_STATUS_PARMS lsp; + + lsp = (LPMCI_STATUS_PARMS)(void*)dwParam2; + TRACE("Changing %08lx to %08lx\n", lsp->dwReturn, (DWORD)LOWORD(lsp->dwReturn)); + lsp->dwReturn = LOWORD(lsp->dwReturn); + } + break; + default: + FIXME("Unsupported value for hiword (%04x) returned by DriverProc(%s)\n", + HIWORD(dwRet), MCI_MessageToString(wMsg)); + } + break; + case MCI_SYSINFO: + switch (dwRet & 0xFFFF0000ul) { + case 0: + case MCI_INTEGER_RETURNED: + /* nothing to do */ + break; + default: + FIXME("Unsupported value for hiword (%04x)\n", HIWORD(dwRet)); + } + break; + default: + if (HIWORD(dwRet)) { + FIXME("Got non null hiword for dwRet=0x%08lx for command %s\n", + dwRet, MCI_MessageToString(wMsg)); + } + break; + } + return LOWORD(dwRet); +} diff --git a/reactos/lib/winmm/message16.c b/reactos/lib/winmm/message16.c new file mode 100644 index 00000000000..deb55af37e4 --- /dev/null +++ b/reactos/lib/winmm/message16.c @@ -0,0 +1,2795 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/* + * MMSYTEM MCI and low level mapping 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 + */ + +#include +#include +#include +#include +#include "wine/winbase16.h" +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winver.h" +#include "wownt32.h" +#include "winemm16.h" +#include "digitalv.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winmm); + +/************************************************************************** + * MMDRV_Callback [internal] + */ +static void MMDRV_Callback(LPWINE_MLD mld, HDRVR hDev, UINT uMsg, DWORD dwParam1, DWORD dwParam2) +{ + TRACE("CB (*%08lx)(%p %08x %08lx %08lx %08lx\n", + mld->dwCallback, hDev, uMsg, mld->dwClientInstance, dwParam1, dwParam2); + + if (!mld->bFrom32 && (mld->dwFlags & DCB_TYPEMASK) == DCB_FUNCTION) + { + WORD args[8]; + /* 16 bit func, call it */ + TRACE("Function (16 bit) !\n"); + + args[7] = HDRVR_16(hDev); + args[6] = uMsg; + args[5] = HIWORD(mld->dwClientInstance); + args[4] = LOWORD(mld->dwClientInstance); + args[3] = HIWORD(dwParam1); + args[2] = LOWORD(dwParam1); + args[1] = HIWORD(dwParam2); + args[0] = LOWORD(dwParam2); + WOWCallback16Ex( mld->dwCallback, WCB16_PASCAL, sizeof(args), args, NULL ); + } else { + DriverCallback(mld->dwCallback, mld->dwFlags, hDev, uMsg, + mld->dwClientInstance, dwParam1, dwParam2); + } +} + +/* ================================= + * A U X M A P P E R S + * ================================= */ + +/************************************************************************** + * MMDRV_Aux_Map16To32A [internal] + */ +static WINMM_MapType MMDRV_Aux_Map16To32A (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Aux_UnMap16To32A [internal] + */ +static WINMM_MapType MMDRV_Aux_UnMap16To32A(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Aux_Map32ATo16 [internal] + */ +static WINMM_MapType MMDRV_Aux_Map32ATo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Aux_UnMap32ATo16 [internal] + */ +static WINMM_MapType MMDRV_Aux_UnMap32ATo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ +#if 0 + case AUXDM_GETDEVCAPS: + lpCaps->wMid = ac16.wMid; + lpCaps->wPid = ac16.wPid; + lpCaps->vDriverVersion = ac16.vDriverVersion; + strcpy(lpCaps->szPname, ac16.szPname); + lpCaps->wTechnology = ac16.wTechnology; + lpCaps->dwSupport = ac16.dwSupport; +#endif + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Aux_Callback [internal] + */ +static void CALLBACK MMDRV_Aux_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD mld = (LPWINE_MLD)dwInstance; + + FIXME("NIY\n"); + MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); +} + +/* ================================= + * M I X E R M A P P E R S + * ================================= */ + +/************************************************************************** + * xMMDRV_Mixer_Map16To32A [internal] + */ +static WINMM_MapType MMDRV_Mixer_Map16To32A (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Mixer_UnMap16To32A [internal] + */ +static WINMM_MapType MMDRV_Mixer_UnMap16To32A(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ +#if 0 + 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; + strcpy(mixcaps->szPname, micA.szPname); + mixcaps->fdwSupport = micA.fdwSupport; + mixcaps->cDestinations = micA.cDestinations; + } + return ret; +#endif + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Mixer_Map32ATo16 [internal] + */ +static WINMM_MapType MMDRV_Mixer_Map32ATo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Mixer_UnMap32ATo16 [internal] + */ +static WINMM_MapType MMDRV_Mixer_UnMap32ATo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Mixer_Callback [internal] + */ +static void CALLBACK MMDRV_Mixer_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD mld = (LPWINE_MLD)dwInstance; + + FIXME("NIY\n"); + MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); +} + +/* ================================= + * M I D I I N M A P P E R S + * ================================= */ + +/************************************************************************** + * MMDRV_MidiIn_Map16To32A [internal] + */ +static WINMM_MapType MMDRV_MidiIn_Map16To32A (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_MidiIn_UnMap16To32A [internal] + */ +static WINMM_MapType MMDRV_MidiIn_UnMap16To32A(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_MidiIn_Map32ATo16 [internal] + */ +static WINMM_MapType MMDRV_MidiIn_Map32ATo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_MidiIn_UnMap32ATo16 [internal] + */ +static WINMM_MapType MMDRV_MidiIn_UnMap32ATo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_MidiIn_Callback [internal] + */ +static void CALLBACK MMDRV_MidiIn_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD mld = (LPWINE_MLD)dwInstance; + + switch (uMsg) { + case MIM_OPEN: + case MIM_CLOSE: + /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ + + case MIM_DATA: + case MIM_MOREDATA: + case MIM_ERROR: + /* dwParam1 & dwParam2 are are data, nothing to do */ + break; + case MIM_LONGDATA: + case MIM_LONGERROR: + /* dwParam1 points to a MidiHdr, work to be done !!! */ + if (mld->bFrom32 && !MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 32 => 16 */ + LPMIDIHDR mh16 = MapSL(dwParam1); + LPMIDIHDR mh32 = *(LPMIDIHDR*)((LPSTR)mh16 - sizeof(LPMIDIHDR)); + + dwParam1 = (DWORD)mh32; + mh32->dwFlags = mh16->dwFlags; + mh32->dwBytesRecorded = mh16->dwBytesRecorded; + if (mh32->reserved >= sizeof(MIDIHDR)) + mh32->dwOffset = mh16->dwOffset; + } else if (!mld->bFrom32 && MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 16 => 32 */ + LPMIDIHDR mh32 = (LPMIDIHDR)(dwParam1); + SEGPTR segmh16 = *(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR)); + LPMIDIHDR mh16 = MapSL(segmh16); + + dwParam1 = (DWORD)segmh16; + mh16->dwFlags = mh32->dwFlags; + mh16->dwBytesRecorded = mh32->dwBytesRecorded; + if (mh16->reserved >= sizeof(MIDIHDR)) + mh16->dwOffset = mh32->dwOffset; + } + /* else { 16 => 16 or 32 => 32, nothing to do, same struct is kept }*/ + break; + /* case MOM_POSITIONCB: */ + default: + ERR("Unknown msg %u\n", uMsg); + } + + MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); +} + +/* ================================= + * M I D I O U T M A P P E R S + * ================================= */ + +/************************************************************************** + * MMDRV_MidiOut_Map16To32A [internal] + */ +static WINMM_MapType MMDRV_MidiOut_Map16To32A (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case MODM_GETNUMDEVS: + case MODM_DATA: + case MODM_RESET: + case MODM_SETVOLUME: + ret = WINMM_MAP_OK; + break; + + case MODM_OPEN: + case MODM_CLOSE: + case MODM_GETVOLUME: + FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); + break; + + case MODM_GETDEVCAPS: + { + LPMIDIOUTCAPSA moc32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMIDIOUTCAPS16) + sizeof(MIDIOUTCAPSA)); + LPMIDIOUTCAPS16 moc16 = MapSL(*lpParam1); + + if (moc32) { + *(LPMIDIOUTCAPS16*)moc32 = moc16; + moc32 = (LPMIDIOUTCAPSA)((LPSTR)moc32 + sizeof(LPMIDIOUTCAPS16)); + *lpParam1 = (DWORD)moc32; + *lpParam2 = sizeof(MIDIOUTCAPSA); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case MODM_PREPARE: + { + LPMIDIHDR mh32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMIDIHDR) + sizeof(MIDIHDR)); + LPMIDIHDR mh16 = MapSL(*lpParam1); + + if (mh32) { + *(LPMIDIHDR*)mh32 = (LPMIDIHDR)*lpParam1; + mh32 = (LPMIDIHDR)((LPSTR)mh32 + sizeof(LPMIDIHDR)); + mh32->lpData = MapSL((SEGPTR)mh16->lpData); + mh32->dwBufferLength = mh16->dwBufferLength; + mh32->dwBytesRecorded = mh16->dwBytesRecorded; + mh32->dwUser = mh16->dwUser; + mh32->dwFlags = mh16->dwFlags; + /* FIXME: nothing on mh32->lpNext */ + /* could link the mh32->lpNext at this level for memory house keeping */ + mh32->dwOffset = (*lpParam2 >= sizeof(MIDIHDR)) ? ((LPMIDIHDR)mh16)->dwOffset : 0; + mh16->lpNext = mh32; /* for reuse in unprepare and write */ + /* store size of passed MIDIHDR?? structure to know if dwOffset is available or not */ + mh16->reserved = *lpParam2; + *lpParam1 = (DWORD)mh32; + *lpParam2 = sizeof(MIDIHDR); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case MODM_UNPREPARE: + case MODM_LONGDATA: + { + LPMIDIHDR mh16 = MapSL(*lpParam1); + LPMIDIHDR mh32 = (LPMIDIHDR)mh16->lpNext; + + *lpParam1 = (DWORD)mh32; + *lpParam2 = sizeof(MIDIHDR); + /* dwBufferLength can be reduced between prepare & write */ + if (wMsg == MODM_LONGDATA && mh32->dwBufferLength < mh16->dwBufferLength) { + ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", + mh32->dwBufferLength, mh16->dwBufferLength); + } else + mh32->dwBufferLength = mh16->dwBufferLength; + ret = WINMM_MAP_OKMEM; + } + break; + + case MODM_CACHEPATCHES: + case MODM_CACHEDRUMPATCHES: + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_MidiOut_UnMap16To32A [internal] + */ +static WINMM_MapType MMDRV_MidiOut_UnMap16To32A(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case MODM_GETNUMDEVS: + case MODM_DATA: + case MODM_RESET: + case MODM_SETVOLUME: + ret = WINMM_MAP_OK; + break; + + case MODM_OPEN: + case MODM_CLOSE: + case MODM_GETVOLUME: + FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); + break; + + case MODM_GETDEVCAPS: + { + LPMIDIOUTCAPSA moc32 = (LPMIDIOUTCAPSA)(*lpParam1); + LPMIDIOUTCAPS16 moc16 = *(LPMIDIOUTCAPS16*)((LPSTR)moc32 - sizeof(LPMIDIOUTCAPS16)); + + moc16->wMid = moc32->wMid; + moc16->wPid = moc32->wPid; + moc16->vDriverVersion = moc32->vDriverVersion; + strcpy(moc16->szPname, moc32->szPname); + moc16->wTechnology = moc32->wTechnology; + moc16->wVoices = moc32->wVoices; + moc16->wNotes = moc32->wNotes; + moc16->wChannelMask = moc32->wChannelMask; + moc16->dwSupport = moc32->dwSupport; + HeapFree(GetProcessHeap(), 0, (LPSTR)moc32 - sizeof(LPMIDIOUTCAPS16)); + ret = WINMM_MAP_OK; + } + break; + case MODM_PREPARE: + case MODM_UNPREPARE: + case MODM_LONGDATA: + { + LPMIDIHDR mh32 = (LPMIDIHDR)(*lpParam1); + LPMIDIHDR mh16 = MapSL(*(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR))); + + assert(mh16->lpNext == mh32); + mh16->dwBufferLength = mh32->dwBufferLength; + mh16->dwBytesRecorded = mh32->dwBytesRecorded; + mh16->dwUser = mh32->dwUser; + mh16->dwFlags = mh32->dwFlags; + if (mh16->reserved >= sizeof(MIDIHDR)) + mh16->dwOffset = mh32->dwOffset; + + if (wMsg == MODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { + HeapFree(GetProcessHeap(), 0, (LPSTR)mh32 - sizeof(LPMIDIHDR)); + mh16->lpNext = 0; + } + ret = WINMM_MAP_OK; + } + break; + + case MODM_CACHEPATCHES: + case MODM_CACHEDRUMPATCHES: + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_MidiOut_Map32ATo16 [internal] + */ +static WINMM_MapType MMDRV_MidiOut_Map32ATo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case MODM_CLOSE: + case MODM_GETNUMDEVS: + case MODM_DATA: + case MODM_RESET: + case MODM_SETVOLUME: + ret = WINMM_MAP_OK; + break; + case MODM_GETDEVCAPS: + { + LPMIDIOUTCAPSA moc32 = (LPMIDIOUTCAPSA)*lpParam1; + LPSTR ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(LPMIDIOUTCAPSA)+sizeof(MIDIOUTCAPS16)); + + if (ptr) { + *(LPMIDIOUTCAPSA*)ptr = moc32; + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + *lpParam1 = (DWORD)MapLS(ptr) + sizeof(LPMIDIOUTCAPSA); + *lpParam2 = sizeof(MIDIOUTCAPS16); + } + break; + case MODM_PREPARE: + { + LPMIDIHDR mh32 = (LPMIDIHDR)*lpParam1; + LPMIDIHDR mh16; + LPVOID ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPMIDIHDR) + sizeof(MIDIHDR) + mh32->dwBufferLength); + + if (ptr) { + *(LPMIDIHDR*)ptr = mh32; + mh16 = (LPMIDIHDR)((LPSTR)ptr + sizeof(LPMIDIHDR)); + *lpParam1 = MapLS(mh16); + mh16->lpData = (LPSTR)*lpParam1 + sizeof(MIDIHDR); + /* data will be copied on WODM_WRITE */ + mh16->dwBufferLength = mh32->dwBufferLength; + mh16->dwBytesRecorded = mh32->dwBytesRecorded; + mh16->dwUser = mh32->dwUser; + mh16->dwFlags = mh32->dwFlags; + /* FIXME: nothing on mh32->lpNext */ + /* could link the mh32->lpNext at this level for memory house keeping */ + mh16->dwOffset = (*lpParam2 >= sizeof(MIDIHDR)) ? mh32->dwOffset : 0; + + mh32->lpNext = (LPMIDIHDR)mh16; /* for reuse in unprepare and write */ + mh32->reserved = *lpParam2; + + TRACE("mh16=%08lx mh16->lpData=%08lx mh32->buflen=%lu mh32->lpData=%08lx\n", + *lpParam1, (DWORD)mh16->lpData, + mh32->dwBufferLength, (DWORD)mh32->lpData); + *lpParam2 = sizeof(MIDIHDR); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case MODM_UNPREPARE: + case MODM_LONGDATA: + { + LPMIDIHDR mh32 = (LPMIDIHDR)(*lpParam1); + LPMIDIHDR mh16 = (LPMIDIHDR)mh32->lpNext; + LPSTR ptr = (LPSTR)mh16 - sizeof(LPMIDIHDR); + + assert(*(LPMIDIHDR*)ptr == mh32); + + if (wMsg == MODM_LONGDATA) + memcpy((LPSTR)mh16 + sizeof(MIDIHDR), mh32->lpData, mh32->dwBufferLength); + + *lpParam1 = MapLS(mh16); + *lpParam2 = sizeof(MIDIHDR); + TRACE("mh16=%08lx mh16->lpData=%08lx mh32->buflen=%lu mh32->lpData=%08lx\n", + *lpParam1, (DWORD)mh16->lpData, mh32->dwBufferLength, (DWORD)mh32->lpData); + + /* dwBufferLength can be reduced between prepare & write */ + if (wMsg == MODM_LONGDATA && mh16->dwBufferLength < mh32->dwBufferLength) { + ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", + mh16->dwBufferLength, mh32->dwBufferLength); + } else + mh16->dwBufferLength = mh32->dwBufferLength; + ret = WINMM_MAP_OKMEM; + } + break; + case MODM_OPEN: + { + LPMIDIOPENDESC mod32 = (LPMIDIOPENDESC)*lpParam1; + LPVOID ptr; + LPMIDIOPENDESC16 mod16; + + /* allocated data are mapped as follows: + LPMIDIOPENDESC ptr to orig lParam1 + DWORD orig dwUser, which is a pointer to DWORD:driver dwInstance + DWORD dwUser passed to driver + MIDIOPENDESC16 mod16: openDesc passed to driver + MIDIOPENSTRMID cIds + */ + ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPMIDIOPENDESC) + 2*sizeof(DWORD) + sizeof(MIDIOPENDESC16) + + mod32->cIds ? (mod32->cIds - 1) * sizeof(MIDIOPENSTRMID) : 0); + + if (ptr) { + SEGPTR segptr = MapLS(ptr); + *(LPMIDIOPENDESC*)ptr = mod32; + *(LPDWORD)((char*)ptr + sizeof(LPMIDIOPENDESC)) = *lpdwUser; + mod16 = (LPMIDIOPENDESC16)((LPSTR)ptr + sizeof(LPMIDIOPENDESC) + 2*sizeof(DWORD)); + + mod16->hMidi = HMIDI_16(mod32->hMidi); + mod16->dwCallback = mod32->dwCallback; + mod16->dwInstance = mod32->dwInstance; + mod16->dnDevNode = mod32->dnDevNode; + mod16->cIds = mod32->cIds; + memcpy(&mod16->rgIds, &mod32->rgIds, mod32->cIds * sizeof(MIDIOPENSTRMID)); + + *lpParam1 = (DWORD)segptr + sizeof(LPMIDIOPENDESC) + 2*sizeof(DWORD); + *lpdwUser = (DWORD)segptr + sizeof(LPMIDIOPENDESC) + sizeof(DWORD); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case MODM_GETVOLUME: + case MODM_CACHEPATCHES: + case MODM_CACHEDRUMPATCHES: + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_MidiOut_UnMap32ATo16 [internal] + */ +static WINMM_MapType MMDRV_MidiOut_UnMap32ATo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case MODM_CLOSE: + case MODM_GETNUMDEVS: + case MODM_DATA: + case MODM_RESET: + case MODM_SETVOLUME: + ret = WINMM_MAP_OK; + break; + case MODM_GETDEVCAPS: + { + LPMIDIOUTCAPS16 moc16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)moc16 - sizeof(LPMIDIOUTCAPSA); + LPMIDIOUTCAPSA moc32 = *(LPMIDIOUTCAPSA*)ptr; + + moc32->wMid = moc16->wMid; + moc32->wPid = moc16->wPid; + moc32->vDriverVersion = moc16->vDriverVersion; + strcpy(moc32->szPname, moc16->szPname); + moc32->wTechnology = moc16->wTechnology; + moc32->wVoices = moc16->wVoices; + moc32->wNotes = moc16->wNotes; + moc32->wChannelMask = moc16->wChannelMask; + moc32->dwSupport = moc16->dwSupport; + UnMapLS( *lpParam1 ); + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + case MODM_PREPARE: + case MODM_UNPREPARE: + case MODM_LONGDATA: + { + LPMIDIHDR mh16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)mh16 - sizeof(LPMIDIHDR); + LPMIDIHDR mh32 = *(LPMIDIHDR*)ptr; + + assert(mh32->lpNext == (LPMIDIHDR)mh16); + UnMapLS( *lpParam1 ); + mh32->dwBytesRecorded = mh16->dwBytesRecorded; + mh32->dwUser = mh16->dwUser; + mh32->dwFlags = mh16->dwFlags; + + if (wMsg == MODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { + HeapFree( GetProcessHeap(), 0, ptr ); + mh32->lpNext = 0; + } + ret = WINMM_MAP_OK; + } + break; + case MODM_OPEN: + { + LPMIDIOPENDESC16 mod16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)mod16 - sizeof(LPMIDIOPENDESC) - 2*sizeof(DWORD); + UnMapLS( *lpParam1 ); + **(DWORD**)(ptr + sizeof(LPMIDIOPENDESC)) = *(LPDWORD)(ptr + sizeof(LPMIDIOPENDESC) + sizeof(DWORD)); + + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + case MODM_GETVOLUME: + case MODM_CACHEPATCHES: + case MODM_CACHEDRUMPATCHES: + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_MidiOut_Callback [internal] + */ +static void CALLBACK MMDRV_MidiOut_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD mld = (LPWINE_MLD)dwInstance; + + switch (uMsg) { + case MOM_OPEN: + case MOM_CLOSE: + /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ + break; + case MOM_DONE: + if (mld->bFrom32 && !MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 32 => 16 */ + LPMIDIHDR mh16 = MapSL(dwParam1); + LPMIDIHDR mh32 = *(LPMIDIHDR*)((LPSTR)mh16 - sizeof(LPMIDIHDR)); + + dwParam1 = (DWORD)mh32; + mh32->dwFlags = mh16->dwFlags; + mh32->dwOffset = mh16->dwOffset; + if (mh32->reserved >= sizeof(MIDIHDR)) + mh32->dwOffset = mh16->dwOffset; + } else if (!mld->bFrom32 && MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 16 => 32 */ + LPMIDIHDR mh32 = (LPMIDIHDR)(dwParam1); + SEGPTR segmh16 = *(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR)); + LPMIDIHDR mh16 = MapSL(segmh16); + + dwParam1 = (DWORD)segmh16; + mh16->dwFlags = mh32->dwFlags; + if (mh16->reserved >= sizeof(MIDIHDR)) + mh16->dwOffset = mh32->dwOffset; + } + /* else { 16 => 16 or 32 => 32, nothing to do, same struct is kept }*/ + break; + /* case MOM_POSITIONCB: */ + default: + ERR("Unknown msg %u\n", uMsg); + } + + MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); +} + +/* ================================= + * W A V E I N M A P P E R S + * ================================= */ + +/************************************************************************** + * MMDRV_WaveIn_Map16To32A [internal] + */ +static WINMM_MapType MMDRV_WaveIn_Map16To32A (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case WIDM_GETNUMDEVS: + case WIDM_RESET: + case WIDM_START: + case WIDM_STOP: + ret = WINMM_MAP_OK; + break; + case WIDM_OPEN: + case WIDM_CLOSE: + FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); + break; + case WIDM_GETDEVCAPS: + { + LPWAVEINCAPSA wic32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPWAVEINCAPS16) + sizeof(WAVEINCAPSA)); + LPWAVEINCAPS16 wic16 = MapSL(*lpParam1); + + if (wic32) { + *(LPWAVEINCAPS16*)wic32 = wic16; + wic32 = (LPWAVEINCAPSA)((LPSTR)wic32 + sizeof(LPWAVEINCAPS16)); + *lpParam1 = (DWORD)wic32; + *lpParam2 = sizeof(WAVEINCAPSA); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WIDM_GETPOS: + { + LPMMTIME mmt32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMMTIME16) + sizeof(MMTIME)); + LPMMTIME16 mmt16 = MapSL(*lpParam1); + + if (mmt32) { + *(LPMMTIME16*)mmt32 = mmt16; + mmt32 = (LPMMTIME)((LPSTR)mmt32 + sizeof(LPMMTIME16)); + + mmt32->wType = mmt16->wType; + *lpParam1 = (DWORD)mmt32; + *lpParam2 = sizeof(MMTIME); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WIDM_PREPARE: + { + LPWAVEHDR wh32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPWAVEHDR) + sizeof(WAVEHDR)); + LPWAVEHDR wh16 = MapSL(*lpParam1); + + if (wh32) { + *(LPWAVEHDR*)wh32 = (LPWAVEHDR)*lpParam1; + wh32 = (LPWAVEHDR)((LPSTR)wh32 + sizeof(LPWAVEHDR)); + wh32->lpData = MapSL((SEGPTR)wh16->lpData); + wh32->dwBufferLength = wh16->dwBufferLength; + wh32->dwBytesRecorded = wh16->dwBytesRecorded; + wh32->dwUser = wh16->dwUser; + wh32->dwFlags = wh16->dwFlags; + wh32->dwLoops = wh16->dwLoops; + /* FIXME: nothing on wh32->lpNext */ + /* could link the wh32->lpNext at this level for memory house keeping */ + wh16->lpNext = wh32; /* for reuse in unprepare and write */ + *lpParam1 = (DWORD)wh32; + *lpParam2 = sizeof(WAVEHDR); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WIDM_ADDBUFFER: + case WIDM_UNPREPARE: + { + LPWAVEHDR wh16 = MapSL(*lpParam1); + LPWAVEHDR wh32 = (LPWAVEHDR)wh16->lpNext; + + *lpParam1 = (DWORD)wh32; + *lpParam2 = sizeof(WAVEHDR); + /* dwBufferLength can be reduced between prepare & write */ + if (wMsg == WIDM_ADDBUFFER && wh32->dwBufferLength < wh16->dwBufferLength) { + ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", + wh32->dwBufferLength, wh16->dwBufferLength); + } else + wh32->dwBufferLength = wh16->dwBufferLength; + ret = WINMM_MAP_OKMEM; + } + break; + case WIDM_MAPPER_STATUS: + /* just a single DWORD */ + *lpParam2 = (DWORD)MapSL(*lpParam2); + ret = WINMM_MAP_OK; + break; + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveIn_UnMap16To32A [internal] + */ +static WINMM_MapType MMDRV_WaveIn_UnMap16To32A(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case WIDM_GETNUMDEVS: + case WIDM_RESET: + case WIDM_START: + case WIDM_STOP: + case WIDM_MAPPER_STATUS: + ret = WINMM_MAP_OK; + break; + case WIDM_OPEN: + case WIDM_CLOSE: + FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); + break; + case WIDM_GETDEVCAPS: + { + LPWAVEINCAPSA wic32 = (LPWAVEINCAPSA)(*lpParam1); + LPWAVEINCAPS16 wic16 = *(LPWAVEINCAPS16*)((LPSTR)wic32 - sizeof(LPWAVEINCAPS16)); + + wic16->wMid = wic32->wMid; + wic16->wPid = wic32->wPid; + wic16->vDriverVersion = wic32->vDriverVersion; + strcpy(wic16->szPname, wic32->szPname); + wic16->dwFormats = wic32->dwFormats; + wic16->wChannels = wic32->wChannels; + HeapFree(GetProcessHeap(), 0, (LPSTR)wic32 - sizeof(LPWAVEINCAPS16)); + ret = WINMM_MAP_OK; + } + break; + case WIDM_GETPOS: + { + LPMMTIME mmt32 = (LPMMTIME)(*lpParam1); + LPMMTIME16 mmt16 = *(LPMMTIME16*)((LPSTR)mmt32 - sizeof(LPMMTIME16)); + + MMSYSTEM_MMTIME32to16(mmt16, mmt32); + HeapFree(GetProcessHeap(), 0, (LPSTR)mmt32 - sizeof(LPMMTIME16)); + ret = WINMM_MAP_OK; + } + break; + case WIDM_ADDBUFFER: + case WIDM_PREPARE: + case WIDM_UNPREPARE: + { + LPWAVEHDR wh32 = (LPWAVEHDR)(*lpParam1); + LPWAVEHDR wh16 = MapSL(*(SEGPTR*)((LPSTR)wh32 - sizeof(LPWAVEHDR))); + + assert(wh16->lpNext == wh32); + wh16->dwBufferLength = wh32->dwBufferLength; + wh16->dwBytesRecorded = wh32->dwBytesRecorded; + wh16->dwUser = wh32->dwUser; + wh16->dwFlags = wh32->dwFlags; + wh16->dwLoops = wh32->dwLoops; + + if (wMsg == WIDM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { + HeapFree(GetProcessHeap(), 0, (LPSTR)wh32 - sizeof(LPWAVEHDR)); + wh16->lpNext = 0; + } + ret = WINMM_MAP_OK; + } + break; + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveIn_Map32ATo16 [internal] + */ +static WINMM_MapType MMDRV_WaveIn_Map32ATo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case WIDM_CLOSE: + case WIDM_GETNUMDEVS: + case WIDM_RESET: + case WIDM_START: + case WIDM_STOP: + ret = WINMM_MAP_OK; + break; + + case WIDM_OPEN: + { + LPWAVEOPENDESC wod32 = (LPWAVEOPENDESC)*lpParam1; + int sz = sizeof(WAVEFORMATEX); + LPVOID ptr; + LPWAVEOPENDESC16 wod16; + + /* allocated data are mapped as follows: + LPWAVEOPENDESC ptr to orig lParam1 + DWORD orig dwUser, which is a pointer to DWORD:driver dwInstance + DWORD dwUser passed to driver + WAVEOPENDESC16 wod16: openDesc passed to driver + WAVEFORMATEX openDesc->lpFormat passed to driver + xxx extra bytes to WAVEFORMATEX + */ + if (wod32->lpFormat->wFormatTag != WAVE_FORMAT_PCM) { + TRACE("Allocating %u extra bytes (%d)\n", ((LPWAVEFORMATEX)wod32->lpFormat)->cbSize, wod32->lpFormat->wFormatTag); + sz += ((LPWAVEFORMATEX)wod32->lpFormat)->cbSize; + } + + ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD) + sizeof(WAVEOPENDESC16) + sz); + + if (ptr) { + SEGPTR seg_ptr = MapLS( ptr ); + *(LPWAVEOPENDESC*)ptr = wod32; + *(LPDWORD)((char*)ptr + sizeof(LPWAVEOPENDESC)) = *lpdwUser; + wod16 = (LPWAVEOPENDESC16)((LPSTR)ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD)); + + wod16->hWave = HWAVE_16(wod32->hWave); + wod16->lpFormat = (LPWAVEFORMATEX)(seg_ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD) + sizeof(WAVEOPENDESC16)); + memcpy(wod16 + 1, wod32->lpFormat, sz); + + wod16->dwCallback = wod32->dwCallback; + wod16->dwInstance = wod32->dwInstance; + wod16->uMappedDeviceID = wod32->uMappedDeviceID; + wod16->dnDevNode = wod32->dnDevNode; + + *lpParam1 = seg_ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD); + *lpdwUser = seg_ptr + sizeof(LPWAVEOPENDESC) + sizeof(DWORD); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WIDM_PREPARE: + { + LPWAVEHDR wh32 = (LPWAVEHDR)*lpParam1; + LPWAVEHDR wh16; + LPVOID ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPWAVEHDR) + sizeof(WAVEHDR) + wh32->dwBufferLength); + + if (ptr) { + SEGPTR seg_ptr = MapLS( ptr ); + *(LPWAVEHDR*)ptr = wh32; + wh16 = (LPWAVEHDR)((LPSTR)ptr + sizeof(LPWAVEHDR)); + wh16->lpData = (LPSTR)seg_ptr + sizeof(LPWAVEHDR) + sizeof(WAVEHDR); + /* data will be copied on WODM_WRITE */ + wh16->dwBufferLength = wh32->dwBufferLength; + wh16->dwBytesRecorded = wh32->dwBytesRecorded; + wh16->dwUser = wh32->dwUser; + wh16->dwFlags = wh32->dwFlags; + wh16->dwLoops = wh32->dwLoops; + /* FIXME: nothing on wh32->lpNext */ + /* could link the wh32->lpNext at this level for memory house keeping */ + wh32->lpNext = wh16; /* for reuse in unprepare and write */ + TRACE("wh16=%08lx wh16->lpData=%08lx wh32->buflen=%lu wh32->lpData=%08lx\n", + seg_ptr + sizeof(LPWAVEHDR), (DWORD)wh16->lpData, + wh32->dwBufferLength, (DWORD)wh32->lpData); + *lpParam1 = seg_ptr + sizeof(LPWAVEHDR); + *lpParam2 = sizeof(WAVEHDR); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WIDM_ADDBUFFER: + case WIDM_UNPREPARE: + { + LPWAVEHDR wh32 = (LPWAVEHDR)(*lpParam1); + LPWAVEHDR wh16 = wh32->lpNext; + LPSTR ptr = (LPSTR)wh16 - sizeof(LPWAVEHDR); + SEGPTR seg_ptr = MapLS( ptr ); + + assert(*(LPWAVEHDR*)ptr == wh32); + + TRACE("wh16=%08lx wh16->lpData=%08lx wh32->buflen=%lu wh32->lpData=%08lx\n", + seg_ptr + sizeof(LPWAVEHDR), (DWORD)wh16->lpData, + wh32->dwBufferLength, (DWORD)wh32->lpData); + + if (wMsg == WIDM_ADDBUFFER) + memcpy((LPSTR)wh16 + sizeof(WAVEHDR), wh32->lpData, wh32->dwBufferLength); + + *lpParam1 = seg_ptr + sizeof(LPWAVEHDR); + *lpParam2 = sizeof(WAVEHDR); + /* dwBufferLength can be reduced between prepare & write */ + if (wMsg == WIDM_ADDBUFFER && wh16->dwBufferLength < wh32->dwBufferLength) { + ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", + wh16->dwBufferLength, wh32->dwBufferLength); + } else + wh16->dwBufferLength = wh32->dwBufferLength; + ret = WINMM_MAP_OKMEM; + } + break; + case WIDM_GETDEVCAPS: + { + LPWAVEINCAPSA wic32 = (LPWAVEINCAPSA)*lpParam1; + LPSTR ptr = HeapAlloc( GetProcessHeap(), 0 ,sizeof(LPWAVEINCAPSA) + sizeof(WAVEINCAPS16)); + + if (ptr) { + *(LPWAVEINCAPSA*)ptr = wic32; + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + *lpParam1 = MapLS(ptr) + sizeof(LPWAVEINCAPSA); + *lpParam2 = sizeof(WAVEINCAPS16); + } + break; + case WIDM_GETPOS: + { + LPMMTIME mmt32 = (LPMMTIME)*lpParam1; + LPSTR ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(LPMMTIME) + sizeof(MMTIME16)); + LPMMTIME16 mmt16 = (LPMMTIME16)(ptr + sizeof(LPMMTIME)); + + if (ptr) { + *(LPMMTIME*)ptr = mmt32; + mmt16->wType = mmt32->wType; + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + *lpParam1 = MapLS(ptr) + sizeof(LPMMTIME); + *lpParam2 = sizeof(MMTIME16); + } + break; + case DRVM_MAPPER_STATUS: + { + LPDWORD p32 = (LPDWORD)*lpParam2; + *lpParam2 = MapLS(p32); + ret = WINMM_MAP_OKMEM; + } + break; + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveIn_UnMap32ATo16 [internal] + */ +static WINMM_MapType MMDRV_WaveIn_UnMap32ATo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case WIDM_CLOSE: + case WIDM_GETNUMDEVS: + case WIDM_RESET: + case WIDM_START: + case WIDM_STOP: + ret = WINMM_MAP_OK; + break; + + case WIDM_OPEN: + { + LPWAVEOPENDESC16 wod16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)wod16 - sizeof(LPWAVEOPENDESC) - 2*sizeof(DWORD); + LPWAVEOPENDESC wod32 = *(LPWAVEOPENDESC*)ptr; + + UnMapLS( *lpParam1 ); + wod32->uMappedDeviceID = wod16->uMappedDeviceID; + **(DWORD**)(ptr + sizeof(LPWAVEOPENDESC)) = *(LPDWORD)(ptr + sizeof(LPWAVEOPENDESC) + sizeof(DWORD)); + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + + case WIDM_ADDBUFFER: + case WIDM_PREPARE: + case WIDM_UNPREPARE: + { + LPWAVEHDR wh16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)wh16 - sizeof(LPWAVEHDR); + LPWAVEHDR wh32 = *(LPWAVEHDR*)ptr; + + assert(wh32->lpNext == wh16); + wh32->dwBytesRecorded = wh16->dwBytesRecorded; + wh32->dwUser = wh16->dwUser; + wh32->dwFlags = wh16->dwFlags; + wh32->dwLoops = wh16->dwLoops; + UnMapLS( *lpParam1 ); + + if (wMsg == WIDM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { + HeapFree( GetProcessHeap(), 0, ptr ); + wh32->lpNext = 0; + } + ret = WINMM_MAP_OK; + } + break; + case WIDM_GETDEVCAPS: + { + LPWAVEINCAPS16 wic16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)wic16 - sizeof(LPWAVEINCAPSA); + LPWAVEINCAPSA wic32 = *(LPWAVEINCAPSA*)ptr; + + wic32->wMid = wic16->wMid; + wic32->wPid = wic16->wPid; + wic32->vDriverVersion = wic16->vDriverVersion; + strcpy(wic32->szPname, wic16->szPname); + wic32->dwFormats = wic16->dwFormats; + wic32->wChannels = wic16->wChannels; + UnMapLS( *lpParam1 ); + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + case WIDM_GETPOS: + { + LPMMTIME16 mmt16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)mmt16 - sizeof(LPMMTIME); + LPMMTIME mmt32 = *(LPMMTIME*)ptr; + + MMSYSTEM_MMTIME16to32(mmt32, mmt16); + UnMapLS( *lpParam1 ); + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + case DRVM_MAPPER_STATUS: + { + UnMapLS( *lpParam2 ); + ret = WINMM_MAP_OK; + } + break; + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveIn_Callback [internal] + */ +static void CALLBACK MMDRV_WaveIn_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD mld = (LPWINE_MLD)dwInstance; + + switch (uMsg) { + case WIM_OPEN: + case WIM_CLOSE: + /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ + break; + case WIM_DATA: + if (mld->bFrom32 && !MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 32 => 16 */ + LPWAVEHDR wh16 = MapSL(dwParam1); + LPWAVEHDR wh32 = *(LPWAVEHDR*)((LPSTR)wh16 - sizeof(LPWAVEHDR)); + + dwParam1 = (DWORD)wh32; + wh32->dwFlags = wh16->dwFlags; + wh32->dwBytesRecorded = wh16->dwBytesRecorded; + } else if (!mld->bFrom32 && MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 16 => 32 */ + LPWAVEHDR wh32 = (LPWAVEHDR)(dwParam1); + SEGPTR segwh16 = *(SEGPTR*)((LPSTR)wh32 - sizeof(LPWAVEHDR)); + LPWAVEHDR wh16 = MapSL(segwh16); + + dwParam1 = (DWORD)segwh16; + wh16->dwFlags = wh32->dwFlags; + wh16->dwBytesRecorded = wh32->dwBytesRecorded; + } + /* else { 16 => 16 or 32 => 32, nothing to do, same struct is kept }*/ + break; + default: + ERR("Unknown msg %u\n", uMsg); + } + + MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); +} + +/* ================================= + * W A V E O U T M A P P E R S + * ================================= */ + +/************************************************************************** + * MMDRV_WaveOut_Map16To32A [internal] + */ +static WINMM_MapType MMDRV_WaveOut_Map16To32A (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + /* nothing to do */ + case WODM_BREAKLOOP: + case WODM_CLOSE: + case WODM_GETNUMDEVS: + case WODM_PAUSE: + case WODM_RESET: + case WODM_RESTART: + case WODM_SETPITCH: + case WODM_SETPLAYBACKRATE: + case WODM_SETVOLUME: + ret = WINMM_MAP_OK; + break; + + case WODM_GETPITCH: + case WODM_GETPLAYBACKRATE: + case WODM_GETVOLUME: + case WODM_OPEN: + FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); + break; + + case WODM_GETDEVCAPS: + { + LPWAVEOUTCAPSA woc32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPWAVEOUTCAPS16) + sizeof(WAVEOUTCAPSA)); + LPWAVEOUTCAPS16 woc16 = MapSL(*lpParam1); + + if (woc32) { + *(LPWAVEOUTCAPS16*)woc32 = woc16; + woc32 = (LPWAVEOUTCAPSA)((LPSTR)woc32 + sizeof(LPWAVEOUTCAPS16)); + *lpParam1 = (DWORD)woc32; + *lpParam2 = sizeof(WAVEOUTCAPSA); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WODM_GETPOS: + { + LPMMTIME mmt32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMMTIME16) + sizeof(MMTIME)); + LPMMTIME16 mmt16 = MapSL(*lpParam1); + + if (mmt32) { + *(LPMMTIME16*)mmt32 = mmt16; + mmt32 = (LPMMTIME)((LPSTR)mmt32 + sizeof(LPMMTIME16)); + + mmt32->wType = mmt16->wType; + *lpParam1 = (DWORD)mmt32; + *lpParam2 = sizeof(MMTIME); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WODM_PREPARE: + { + LPWAVEHDR wh32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPWAVEHDR) + sizeof(WAVEHDR)); + LPWAVEHDR wh16 = MapSL(*lpParam1); + + if (wh32) { + *(LPWAVEHDR*)wh32 = (LPWAVEHDR)*lpParam1; + wh32 = (LPWAVEHDR)((LPSTR)wh32 + sizeof(LPWAVEHDR)); + wh32->lpData = MapSL((SEGPTR)wh16->lpData); + wh32->dwBufferLength = wh16->dwBufferLength; + wh32->dwBytesRecorded = wh16->dwBytesRecorded; + wh32->dwUser = wh16->dwUser; + wh32->dwFlags = wh16->dwFlags; + wh32->dwLoops = wh16->dwLoops; + /* FIXME: nothing on wh32->lpNext */ + /* could link the wh32->lpNext at this level for memory house keeping */ + wh16->lpNext = wh32; /* for reuse in unprepare and write */ + *lpParam1 = (DWORD)wh32; + *lpParam2 = sizeof(WAVEHDR); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WODM_UNPREPARE: + case WODM_WRITE: + { + LPWAVEHDR wh16 = MapSL(*lpParam1); + LPWAVEHDR wh32 = (LPWAVEHDR)wh16->lpNext; + + *lpParam1 = (DWORD)wh32; + *lpParam2 = sizeof(WAVEHDR); + /* dwBufferLength can be reduced between prepare & write */ + if (wMsg == WODM_WRITE && wh32->dwBufferLength < wh16->dwBufferLength) { + ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", + wh32->dwBufferLength, wh16->dwBufferLength); + } else + wh32->dwBufferLength = wh16->dwBufferLength; + ret = WINMM_MAP_OKMEM; + } + break; + case WODM_MAPPER_STATUS: + *lpParam2 = (DWORD)MapSL(*lpParam2); + ret = WINMM_MAP_OK; + break; + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveOut_UnMap16To32A [internal] + */ +static WINMM_MapType MMDRV_WaveOut_UnMap16To32A(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + /* nothing to do */ + case WODM_BREAKLOOP: + case WODM_CLOSE: + case WODM_GETNUMDEVS: + case WODM_PAUSE: + case WODM_RESET: + case WODM_RESTART: + case WODM_SETPITCH: + case WODM_SETPLAYBACKRATE: + case WODM_SETVOLUME: + case WODM_MAPPER_STATUS: + ret = WINMM_MAP_OK; + break; + + case WODM_GETPITCH: + case WODM_GETPLAYBACKRATE: + case WODM_GETVOLUME: + case WODM_OPEN: + FIXME("Shouldn't be used: those 16 bit functions use the 32 bit interface\n"); + break; + + case WODM_GETDEVCAPS: + { + LPWAVEOUTCAPSA woc32 = (LPWAVEOUTCAPSA)(*lpParam1); + LPWAVEOUTCAPS16 woc16 = *(LPWAVEOUTCAPS16*)((LPSTR)woc32 - sizeof(LPWAVEOUTCAPS16)); + + woc16->wMid = woc32->wMid; + woc16->wPid = woc32->wPid; + woc16->vDriverVersion = woc32->vDriverVersion; + strcpy(woc16->szPname, woc32->szPname); + woc16->dwFormats = woc32->dwFormats; + woc16->wChannels = woc32->wChannels; + woc16->dwSupport = woc32->dwSupport; + HeapFree(GetProcessHeap(), 0, (LPSTR)woc32 - sizeof(LPWAVEOUTCAPS16)); + ret = WINMM_MAP_OK; + } + break; + case WODM_GETPOS: + { + LPMMTIME mmt32 = (LPMMTIME)(*lpParam1); + LPMMTIME16 mmt16 = *(LPMMTIME16*)((LPSTR)mmt32 - sizeof(LPMMTIME16)); + + MMSYSTEM_MMTIME32to16(mmt16, mmt32); + HeapFree(GetProcessHeap(), 0, (LPSTR)mmt32 - sizeof(LPMMTIME16)); + ret = WINMM_MAP_OK; + } + break; + case WODM_PREPARE: + case WODM_UNPREPARE: + case WODM_WRITE: + { + LPWAVEHDR wh32 = (LPWAVEHDR)(*lpParam1); + LPWAVEHDR wh16 = MapSL(*(SEGPTR*)((LPSTR)wh32 - sizeof(LPWAVEHDR))); + + assert(wh16->lpNext == wh32); + wh16->dwBufferLength = wh32->dwBufferLength; + wh16->dwBytesRecorded = wh32->dwBytesRecorded; + wh16->dwUser = wh32->dwUser; + wh16->dwFlags = wh32->dwFlags; + wh16->dwLoops = wh32->dwLoops; + + if (wMsg == WODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { + HeapFree(GetProcessHeap(), 0, (LPSTR)wh32 - sizeof(LPWAVEHDR)); + wh16->lpNext = 0; + } + ret = WINMM_MAP_OK; + } + break; + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveOut_Map32ATo16 [internal] + */ +static WINMM_MapType MMDRV_WaveOut_Map32ATo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + WINMM_MapType ret; + + switch (wMsg) { + /* nothing to do */ + case WODM_BREAKLOOP: + case WODM_CLOSE: + case WODM_GETNUMDEVS: + case WODM_PAUSE: + case WODM_RESET: + case WODM_RESTART: + case WODM_SETPITCH: + case WODM_SETPLAYBACKRATE: + case WODM_SETVOLUME: + ret = WINMM_MAP_OK; + break; + + case WODM_GETDEVCAPS: + { + LPWAVEOUTCAPSA woc32 = (LPWAVEOUTCAPSA)*lpParam1; + LPSTR ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPWAVEOUTCAPSA) + sizeof(WAVEOUTCAPS16)); + + if (ptr) { + *(LPWAVEOUTCAPSA*)ptr = woc32; + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + *lpParam1 = MapLS(ptr) + sizeof(LPWAVEOUTCAPSA); + *lpParam2 = sizeof(WAVEOUTCAPS16); + } + break; + case WODM_GETPITCH: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + case WODM_GETPLAYBACKRATE: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + case WODM_GETPOS: + { + LPMMTIME mmt32 = (LPMMTIME)*lpParam1; + LPSTR ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(LPMMTIME) + sizeof(MMTIME16)); + LPMMTIME16 mmt16 = (LPMMTIME16)(ptr + sizeof(LPMMTIME)); + + if (ptr) { + *(LPMMTIME*)ptr = mmt32; + mmt16->wType = mmt32->wType; + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + *lpParam1 = MapLS(ptr) + sizeof(LPMMTIME); + *lpParam2 = sizeof(MMTIME16); + } + break; + case WODM_GETVOLUME: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + case WODM_OPEN: + { + LPWAVEOPENDESC wod32 = (LPWAVEOPENDESC)*lpParam1; + int sz = sizeof(WAVEFORMATEX); + LPVOID ptr; + LPWAVEOPENDESC16 wod16; + + /* allocated data are mapped as follows: + LPWAVEOPENDESC ptr to orig lParam1 + DWORD orig dwUser, which is a pointer to DWORD:driver dwInstance + DWORD dwUser passed to driver + WAVEOPENDESC16 wod16: openDesc passed to driver + WAVEFORMATEX openDesc->lpFormat passed to driver + xxx extra bytes to WAVEFORMATEX + */ + if (wod32->lpFormat->wFormatTag != WAVE_FORMAT_PCM) { + TRACE("Allocating %u extra bytes (%d)\n", ((LPWAVEFORMATEX)wod32->lpFormat)->cbSize, wod32->lpFormat->wFormatTag); + sz += ((LPWAVEFORMATEX)wod32->lpFormat)->cbSize; + } + + ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD) + sizeof(WAVEOPENDESC16) + sz); + + if (ptr) { + SEGPTR seg_ptr = MapLS( ptr ); + *(LPWAVEOPENDESC*)ptr = wod32; + *(LPDWORD)((char*)ptr + sizeof(LPWAVEOPENDESC)) = *lpdwUser; + wod16 = (LPWAVEOPENDESC16)((LPSTR)ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD)); + + wod16->hWave = HWAVE_16(wod32->hWave); + wod16->lpFormat = (LPWAVEFORMATEX)(seg_ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD) + sizeof(WAVEOPENDESC16)); + memcpy(wod16 + 1, wod32->lpFormat, sz); + + wod16->dwCallback = wod32->dwCallback; + wod16->dwInstance = wod32->dwInstance; + wod16->uMappedDeviceID = wod32->uMappedDeviceID; + wod16->dnDevNode = wod32->dnDevNode; + + *lpParam1 = seg_ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD); + *lpdwUser = seg_ptr + sizeof(LPWAVEOPENDESC) + sizeof(DWORD); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WODM_PREPARE: + { + LPWAVEHDR wh32 = (LPWAVEHDR)*lpParam1; + LPWAVEHDR wh16; + LPVOID ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPWAVEHDR) + sizeof(WAVEHDR) + wh32->dwBufferLength); + + if (ptr) { + SEGPTR seg_ptr = MapLS( ptr ); + *(LPWAVEHDR*)ptr = wh32; + wh16 = (LPWAVEHDR)((LPSTR)ptr + sizeof(LPWAVEHDR)); + wh16->lpData = (LPSTR)seg_ptr + sizeof(LPWAVEHDR) + sizeof(WAVEHDR); + /* data will be copied on WODM_WRITE */ + wh16->dwBufferLength = wh32->dwBufferLength; + wh16->dwBytesRecorded = wh32->dwBytesRecorded; + wh16->dwUser = wh32->dwUser; + wh16->dwFlags = wh32->dwFlags; + wh16->dwLoops = wh32->dwLoops; + /* FIXME: nothing on wh32->lpNext */ + /* could link the wh32->lpNext at this level for memory house keeping */ + wh32->lpNext = wh16; /* for reuse in unprepare and write */ + TRACE("wh16=%08lx wh16->lpData=%08lx wh32->buflen=%lu wh32->lpData=%08lx\n", + seg_ptr + sizeof(LPWAVEHDR), (DWORD)wh16->lpData, + wh32->dwBufferLength, (DWORD)wh32->lpData); + *lpParam1 = seg_ptr + sizeof(LPWAVEHDR); + *lpParam2 = sizeof(WAVEHDR); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WODM_UNPREPARE: + case WODM_WRITE: + { + LPWAVEHDR wh32 = (LPWAVEHDR)(*lpParam1); + LPWAVEHDR wh16 = wh32->lpNext; + LPSTR ptr = (LPSTR)wh16 - sizeof(LPWAVEHDR); + SEGPTR seg_ptr = MapLS( ptr ); + + assert(*(LPWAVEHDR*)ptr == wh32); + + TRACE("wh16=%08lx wh16->lpData=%08lx wh32->buflen=%lu wh32->lpData=%08lx\n", + seg_ptr + sizeof(LPWAVEHDR), (DWORD)wh16->lpData, + wh32->dwBufferLength, (DWORD)wh32->lpData); + + if (wMsg == WODM_WRITE) + memcpy((LPSTR)wh16 + sizeof(WAVEHDR), wh32->lpData, wh32->dwBufferLength); + + *lpParam1 = seg_ptr + sizeof(LPWAVEHDR); + *lpParam2 = sizeof(WAVEHDR); + /* dwBufferLength can be reduced between prepare & write */ + if (wMsg == WODM_WRITE && wh16->dwBufferLength < wh32->dwBufferLength) { + ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", + wh16->dwBufferLength, wh32->dwBufferLength); + } else + wh16->dwBufferLength = wh32->dwBufferLength; + ret = WINMM_MAP_OKMEM; + } + break; + case DRVM_MAPPER_STATUS: + { + LPDWORD p32 = (LPDWORD)*lpParam2; + *lpParam2 = MapLS(p32); + ret = WINMM_MAP_OKMEM; + } + break; + default: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveOut_UnMap32ATo16 [internal] + */ +static WINMM_MapType MMDRV_WaveOut_UnMap32ATo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + WINMM_MapType ret; + + switch (wMsg) { + /* nothing to do */ + case WODM_BREAKLOOP: + case WODM_CLOSE: + case WODM_GETNUMDEVS: + case WODM_PAUSE: + case WODM_RESET: + case WODM_RESTART: + case WODM_SETPITCH: + case WODM_SETPLAYBACKRATE: + case WODM_SETVOLUME: + ret = WINMM_MAP_OK; + break; + + case WODM_GETDEVCAPS: + { + LPWAVEOUTCAPS16 woc16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)woc16 - sizeof(LPWAVEOUTCAPSA); + LPWAVEOUTCAPSA woc32 = *(LPWAVEOUTCAPSA*)ptr; + + woc32->wMid = woc16->wMid; + woc32->wPid = woc16->wPid; + woc32->vDriverVersion = woc16->vDriverVersion; + strcpy(woc32->szPname, woc16->szPname); + woc32->dwFormats = woc16->dwFormats; + woc32->wChannels = woc16->wChannels; + woc32->dwSupport = woc16->dwSupport; + UnMapLS( *lpParam1 ); + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + case WODM_GETPITCH: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + case WODM_GETPLAYBACKRATE: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + case WODM_GETPOS: + { + LPMMTIME16 mmt16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)mmt16 - sizeof(LPMMTIME); + LPMMTIME mmt32 = *(LPMMTIME*)ptr; + + MMSYSTEM_MMTIME16to32(mmt32, mmt16); + UnMapLS( *lpParam1 ); + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + case WODM_OPEN: + { + LPWAVEOPENDESC16 wod16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)wod16 - sizeof(LPWAVEOPENDESC) - 2*sizeof(DWORD); + LPWAVEOPENDESC wod32 = *(LPWAVEOPENDESC*)ptr; + + wod32->uMappedDeviceID = wod16->uMappedDeviceID; + **(DWORD**)(ptr + sizeof(LPWAVEOPENDESC)) = *(LPDWORD)(ptr + sizeof(LPWAVEOPENDESC) + sizeof(DWORD)); + UnMapLS( *lpParam1 ); + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + case WODM_PREPARE: + case WODM_UNPREPARE: + case WODM_WRITE: + { + LPWAVEHDR wh16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)wh16 - sizeof(LPWAVEHDR); + LPWAVEHDR wh32 = *(LPWAVEHDR*)ptr; + + assert(wh32->lpNext == wh16); + wh32->dwBytesRecorded = wh16->dwBytesRecorded; + wh32->dwUser = wh16->dwUser; + wh32->dwFlags = wh16->dwFlags; + wh32->dwLoops = wh16->dwLoops; + + UnMapLS( *lpParam1 ); + if (wMsg == WODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { + HeapFree( GetProcessHeap(), 0, ptr ); + wh32->lpNext = 0; + } + ret = WINMM_MAP_OK; + } + break; + case WODM_GETVOLUME: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + case DRVM_MAPPER_STATUS: + { + UnMapLS( *lpParam2 ); + ret = WINMM_MAP_OK; + } + break; + default: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveOut_Callback [internal] + */ +static void CALLBACK MMDRV_WaveOut_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD mld = (LPWINE_MLD)dwInstance; + + switch (uMsg) { + case WOM_OPEN: + case WOM_CLOSE: + /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ + break; + case WOM_DONE: + if (mld->bFrom32 && !MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 32 => 16 */ + LPWAVEHDR wh16 = MapSL(dwParam1); + LPWAVEHDR wh32 = *(LPWAVEHDR*)((LPSTR)wh16 - sizeof(LPWAVEHDR)); + + dwParam1 = (DWORD)wh32; + wh32->dwFlags = wh16->dwFlags; + } else if (!mld->bFrom32 && MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 16 => 32 */ + LPWAVEHDR wh32 = (LPWAVEHDR)(dwParam1); + SEGPTR segwh16 = *(SEGPTR*)((LPSTR)wh32 - sizeof(LPWAVEHDR)); + LPWAVEHDR wh16 = MapSL(segwh16); + + dwParam1 = (DWORD)segwh16; + wh16->dwFlags = wh32->dwFlags; + } + /* else { 16 => 16 or 32 => 32, nothing to do, same struct is kept }*/ + break; + default: + ERR("Unknown msg %u\n", uMsg); + } + + MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); +} + +/* ================================= + * M A P P E R S H A N D L I N G + * ================================= */ + +static LRESULT MMDRV_CallMMDrvFunc16(DWORD fp16, WORD dev, WORD msg, LONG instance, + LONG lp1, LONG lp2) +{ + WORD args[8]; + DWORD ret; + + args[7] = dev; + args[6] = msg; + args[5] = HIWORD(instance); + args[4] = LOWORD(instance); + args[3] = HIWORD(lp1); + args[2] = LOWORD(lp1); + args[1] = HIWORD(lp2); + args[0] = LOWORD(lp2); + WOWCallback16Ex( fp16, WCB16_PASCAL, sizeof(args), args, &ret ); + return LOWORD(ret); +} + +/************************************************************************** + * MMDRV_GetDescription16 [internal] + */ +static BOOL MMDRV_GetDescription16(const char* fname, char* buf, int buflen) +{ + OFSTRUCT ofs; + HFILE hFile; + WORD w; + DWORD dw; + BOOL ret = FALSE; + + if ((hFile = OpenFile(fname, &ofs, OF_READ | OF_SHARE_DENY_WRITE)) == HFILE_ERROR) { + ERR("Can't open file %s (builtin driver ?)\n", fname); + return FALSE; + } + +#define E(_x) do {TRACE _x;goto theEnd;} while(0) + + if (_lread(hFile, &w, 2) != 2) E(("Can't read sig\n")); + if (w != ('Z' * 256 + 'M')) E(("Bad sig %04x\n", w)); + if (_llseek(hFile, 0x3C, SEEK_SET) < 0) E(("Can't seek to ext header offset\n")); + if (_lread(hFile, &dw, 4) != 4) E(("Can't read ext header offset\n")); + if (_llseek(hFile, dw + 0x2C, SEEK_SET) < 0) E(("Can't seek to ext header.nr table %lu\n", dw+0x2C)); + if (_lread(hFile, &dw, 4) != 4) E(("Can't read nr table offset\n")); + if (_llseek(hFile, dw, SEEK_SET) < 0) E(("Can't seek to nr table %lu\n", dw)); + if (_lread(hFile, buf, 1) != 1) E(("Can't read descr length\n")); + buflen = min((int)(unsigned)(BYTE)buf[0], buflen - 1); + if (_lread(hFile, buf, buflen) != buflen) E(("Can't read descr (%d)\n", buflen)); + buf[buflen] = '\0'; + ret = TRUE; + TRACE("Got '%s' [%d]\n", buf, buflen); +theEnd: + _lclose(hFile); + return ret; +} + +/****************************************************************** + * MMDRV_LoadMMDrvFunc16 + * + */ +unsigned MMDRV_LoadMMDrvFunc16(LPCSTR drvName, LPWINE_DRIVER d, + LPWINE_MM_DRIVER lpDrv) +{ + WINEMM_msgFunc16 func; + unsigned count = 0; + char buffer[128]; + /* + * DESCRIPTION 'wave,aux,mixer:Creative Labs Sound Blaster 16 Driver' + * The beginning of the module description indicates the driver supports + * waveform, auxiliary, and mixer devices. Use one of the following + * device-type names, followed by a colon (:) to indicate the type of + * device your driver supports. If the driver supports more than one + * type of device, separate each device-type name with a comma (,). + * + * wave for waveform audio devices + * wavemapper for wave mappers + * midi for MIDI audio devices + * midimapper for midi mappers + * aux for auxiliary audio devices + * mixer for mixer devices + */ + + if (d->d.d16.hDriver16) { + HMODULE16 hMod16 = GetDriverModuleHandle16(d->d.d16.hDriver16); + +#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); } + +#define A(_x,_y) AA(hMod16,_x,_y,16,GetProcAddress16) + 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 +#undef AA + } + if (TRACE_ON(winmm)) { + if (MMDRV_GetDescription16(drvName, buffer, sizeof(buffer))) + TRACE("%s => %s\n", drvName, buffer); + else + TRACE("%s => No description\n", drvName); + } + + return count; +} + +/* ================================= + * M C I + * ================================= */ + +/************************************************************************** + * MCI_MapMsg16To32A [internal] + */ +static WINMM_MapType MCI_MapMsg16To32A(WORD uDevType, WORD wMsg, DWORD* lParam) +{ + if (*lParam == 0) + return WINMM_MAP_OK; + /* FIXME: to add also (with seg/linear modifications to do): + * MCI_LIST, MCI_LOAD, MCI_QUALITY, MCI_RESERVE, MCI_RESTORE, MCI_SAVE + * MCI_SETAUDIO, MCI_SETTUNER, MCI_SETVIDEO + */ + switch (wMsg) { + /* case MCI_CAPTURE */ + case MCI_CLOSE: + case MCI_CLOSE_DRIVER: + case MCI_CONFIGURE: + case MCI_COPY: + case MCI_CUE: + case MCI_CUT: + case MCI_DELETE: + case MCI_FREEZE: + case MCI_GETDEVCAPS: + /* case MCI_INDEX: */ + /* case MCI_MARK: */ + /* case MCI_MONITOR: */ + case MCI_PASTE: + case MCI_PAUSE: + case MCI_PLAY: + case MCI_PUT: + case MCI_REALIZE: + case MCI_RECORD: + case MCI_RESUME: + case MCI_SEEK: + case MCI_SET: + /* case MCI_SETTIMECODE:*/ + /* case MCI_SIGNAL:*/ + case MCI_SPIN: + case MCI_STATUS: /* FIXME: is wrong for digital video */ + case MCI_STEP: + case MCI_STOP: + /* case MCI_UNDO: */ + case MCI_UNFREEZE: + case MCI_UPDATE: + case MCI_WHERE: + *lParam = (DWORD)MapSL(*lParam); + return WINMM_MAP_OK; + case MCI_WINDOW: + /* in fact, I would also need the dwFlags... to see + * which members of lParam are effectively used + */ + *lParam = (DWORD)MapSL(*lParam); + FIXME("Current mapping may be wrong\n"); + break; + case MCI_BREAK: + { + LPMCI_BREAK_PARMS mbp32 = HeapAlloc(GetProcessHeap(), 0, sizeof(MCI_BREAK_PARMS)); + LPMCI_BREAK_PARMS16 mbp16 = MapSL(*lParam); + + if (mbp32) { + mbp32->dwCallback = mbp16->dwCallback; + mbp32->nVirtKey = mbp16->nVirtKey; + mbp32->hwndBreak = HWND_32(mbp16->hwndBreak); + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (DWORD)mbp32; + } + return WINMM_MAP_OKMEM; + case MCI_ESCAPE: + { + LPMCI_VD_ESCAPE_PARMSA mvep32a = HeapAlloc(GetProcessHeap(), 0, sizeof(MCI_VD_ESCAPE_PARMSA)); + LPMCI_VD_ESCAPE_PARMS16 mvep16 = MapSL(*lParam); + + if (mvep32a) { + mvep32a->dwCallback = mvep16->dwCallback; + mvep32a->lpstrCommand = MapSL(mvep16->lpstrCommand); + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (DWORD)mvep32a; + } + return WINMM_MAP_OKMEM; + case MCI_INFO: + { + LPMCI_INFO_PARMSA mip32a = HeapAlloc(GetProcessHeap(), 0, sizeof(MCI_INFO_PARMSA)); + LPMCI_INFO_PARMS16 mip16 = MapSL(*lParam); + + /* FIXME this is wrong if device is of type + * MCI_DEVTYPE_DIGITAL_VIDEO, some members are not mapped + */ + if (mip32a) { + mip32a->dwCallback = mip16->dwCallback; + mip32a->lpstrReturn = MapSL(mip16->lpstrReturn); + mip32a->dwRetSize = mip16->dwRetSize; + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (DWORD)mip32a; + } + return WINMM_MAP_OKMEM; + case MCI_OPEN: + case MCI_OPEN_DRIVER: + { + LPMCI_OPEN_PARMSA mop32a = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMCI_OPEN_PARMS16) + sizeof(MCI_OPEN_PARMSA) + 2 * sizeof(DWORD)); + LPMCI_OPEN_PARMS16 mop16 = MapSL(*lParam); + + if (mop32a) { + *(LPMCI_OPEN_PARMS16*)(mop32a) = mop16; + mop32a = (LPMCI_OPEN_PARMSA)((char*)mop32a + sizeof(LPMCI_OPEN_PARMS16)); + mop32a->dwCallback = mop16->dwCallback; + mop32a->wDeviceID = mop16->wDeviceID; + mop32a->lpstrDeviceType = MapSL(mop16->lpstrDeviceType); + mop32a->lpstrElementName = MapSL(mop16->lpstrElementName); + mop32a->lpstrAlias = MapSL(mop16->lpstrAlias); + /* copy extended information if any... + * FIXME: this may seg fault if initial structure does not contain them and + * the reads after msip16 fail under LDT limits... + * NOTE: this should be split in two. First pass, while calling MCI_OPEN, and + * should not take care of extended parameters, and should be used by MCI_Open + * to fetch uDevType. When, this is known, the mapping for sending the + * MCI_OPEN_DRIVER shall be done depending on uDevType. + */ + memcpy(mop32a + 1, mop16 + 1, 2 * sizeof(DWORD)); + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (DWORD)mop32a; + } + return WINMM_MAP_OKMEM; + case MCI_SYSINFO: + { + LPMCI_SYSINFO_PARMSA msip32a = HeapAlloc(GetProcessHeap(), 0, sizeof(MCI_SYSINFO_PARMSA)); + LPMCI_SYSINFO_PARMS16 msip16 = MapSL(*lParam); + + if (msip32a) { + msip32a->dwCallback = msip16->dwCallback; + msip32a->lpstrReturn = MapSL(msip16->lpstrReturn); + msip32a->dwRetSize = msip16->dwRetSize; + msip32a->dwNumber = msip16->dwNumber; + msip32a->wDeviceType = msip16->wDeviceType; + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (DWORD)msip32a; + } + return WINMM_MAP_OKMEM; + case MCI_SOUND: + { + LPMCI_SOUND_PARMS mbp32 = HeapAlloc(GetProcessHeap(), 0, sizeof(MCI_SOUND_PARMS)); + LPMCI_SOUND_PARMS16 mbp16 = MapSL(*lParam); + + if (mbp32) { + mbp32->dwCallback = mbp16->dwCallback; + mbp32->lpstrSoundName = MapSL(mbp16->lpstrSoundName); + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (DWORD)mbp32; + } + return WINMM_MAP_OKMEM; + case DRV_LOAD: + case DRV_ENABLE: + case DRV_OPEN: + case DRV_CLOSE: + case DRV_DISABLE: + case DRV_FREE: + case DRV_CONFIGURE: + case DRV_QUERYCONFIGURE: + case DRV_INSTALL: + case DRV_REMOVE: + case DRV_EXITSESSION: + case DRV_EXITAPPLICATION: + case DRV_POWER: + FIXME("This is a hack\n"); + return WINMM_MAP_OK; + + default: + WARN("Don't know how to map msg=%s\n", MCI_MessageToString(wMsg)); + } + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MCI_UnMapMsg16To32A [internal] + */ +static WINMM_MapType MCI_UnMapMsg16To32A(WORD uDevType, WORD wMsg, DWORD lParam) +{ + switch (wMsg) { + /* case MCI_CAPTURE */ + case MCI_CLOSE: + case MCI_CLOSE_DRIVER: + case MCI_CONFIGURE: + case MCI_COPY: + case MCI_CUE: + case MCI_CUT: + case MCI_DELETE: + case MCI_FREEZE: + case MCI_GETDEVCAPS: + /* case MCI_INDEX: */ + /* case MCI_MARK: */ + /* case MCI_MONITOR: */ + case MCI_PASTE: + case MCI_PAUSE: + case MCI_PLAY: + case MCI_PUT: + case MCI_REALIZE: + case MCI_RECORD: + case MCI_RESUME: + case MCI_SEEK: + case MCI_SET: + /* case MCI_SETTIMECODE:*/ + /* case MCI_SIGNAL:*/ + case MCI_SPIN: + case MCI_STATUS: + case MCI_STEP: + case MCI_STOP: + /* case MCI_UNDO: */ + case MCI_UNFREEZE: + case MCI_UPDATE: + case MCI_WHERE: + return WINMM_MAP_OK; + + case MCI_WINDOW: + /* FIXME ?? see Map function */ + return WINMM_MAP_OK; + + case MCI_BREAK: + case MCI_ESCAPE: + case MCI_INFO: + case MCI_SYSINFO: + case MCI_SOUND: + HeapFree(GetProcessHeap(), 0, (LPVOID)lParam); + return WINMM_MAP_OK; + case MCI_OPEN: + case MCI_OPEN_DRIVER: + if (lParam) { + LPMCI_OPEN_PARMSA mop32a = (LPMCI_OPEN_PARMSA)lParam; + LPMCI_OPEN_PARMS16 mop16 = *(LPMCI_OPEN_PARMS16*)((char*)mop32a - sizeof(LPMCI_OPEN_PARMS16)); + + mop16->wDeviceID = mop32a->wDeviceID; + if (!HeapFree(GetProcessHeap(), 0, (LPVOID)(lParam - sizeof(LPMCI_OPEN_PARMS16)))) + FIXME("bad free line=%d\n", __LINE__); + } + return WINMM_MAP_OK; + case DRV_LOAD: + case DRV_ENABLE: + case DRV_OPEN: + case DRV_CLOSE: + case DRV_DISABLE: + case DRV_FREE: + case DRV_CONFIGURE: + case DRV_QUERYCONFIGURE: + case DRV_INSTALL: + case DRV_REMOVE: + case DRV_EXITSESSION: + case DRV_EXITAPPLICATION: + case DRV_POWER: + FIXME("This is a hack\n"); + return WINMM_MAP_OK; + default: + FIXME("Map/Unmap internal error on msg=%s\n", MCI_MessageToString(wMsg)); + } + return WINMM_MAP_MSGERROR; +} + +/* + * 0000 stop + * 0001 squeeze signed 4 bytes to 2 bytes *( LPINT16)D = ( INT16)*( LPINT16)S; D += 2; S += 4 + * 0010 squeeze unsigned 4 bytes to 2 bytes *(LPUINT16)D = (UINT16)*(LPUINT16)S; D += 2; S += 4 + * 0100 + * 0101 + * 0110 zero 4 bytes *(DWORD)D = 0 D += 4; S += 4 + * 0111 copy string *(LPSTR*)D = seg dup(*(LPSTR*)S) D += 4; S += 4 + * 1xxx copy xxx + 1 bytes memcpy(D, S, xxx + 1); D += xxx+1; S += xxx+1 + */ + +/************************************************************************** + * MCI_MsgMapper32To16_Create [internal] + * + * Helper for MCI_MapMsg32ATo16. + * Maps the 32 bit pointer (*ptr), of size bytes, to an allocated 16 bit + * segmented pointer. + * map contains a list of action to be performed for the mapping (see list + * above) + * if keep is TRUE, keeps track of in 32 bit ptr in allocated 16 bit area. + */ +static WINMM_MapType MCI_MsgMapper32To16_Create(void** ptr, int size16, DWORD map, BOOLEAN keep) +{ + void* lp = HeapAlloc( GetProcessHeap(), 0, (keep ? sizeof(void**) : 0) + size16 ); + LPBYTE p16, p32; + + if (!lp) { + return WINMM_MAP_NOMEM; + } + p32 = (LPBYTE)(*ptr); + if (keep) { + *(void**)lp = *ptr; + p16 = (LPBYTE)lp + sizeof(void**); + *ptr = (char*)MapLS(lp) + sizeof(void**); + } else { + p16 = lp; + *ptr = (void*)MapLS(lp); + } + + if (map == 0) { + memcpy(p16, p32, size16); + } else { + unsigned nibble; + unsigned sz; + + while (map & 0xF) { + nibble = map & 0xF; + if (nibble & 0x8) { + sz = (nibble & 7) + 1; + memcpy(p16, p32, sz); + p16 += sz; + p32 += sz; + size16 -= sz; /* DEBUG only */ + } else { + switch (nibble) { + case 0x1: + *(LPINT16)p16 = *(LPINT)p32; + p16 += sizeof(INT16); + p32 += sizeof(INT); + size16 -= sizeof(INT16); + break; + case 0x2: + *(LPUINT16)p16 = *(LPUINT)p32; + p16 += sizeof(UINT16); + p32 += sizeof(UINT); + size16 -= sizeof(UINT16); + break; + case 0x6: + *(LPDWORD)p16 = 0; + p16 += sizeof(DWORD); + p32 += sizeof(DWORD); + size16 -= sizeof(DWORD); + break; + case 0x7: + *(SEGPTR *)p16 = MapLS( *(LPSTR *)p32 ); + p16 += sizeof(SEGPTR); + p32 += sizeof(LPSTR); + size16 -= sizeof(SEGPTR); + break; + default: + FIXME("Unknown nibble for mapping (%x)\n", nibble); + } + } + map >>= 4; + } + if (size16 != 0) /* DEBUG only */ + FIXME("Mismatch between 16 bit struct size and map nibbles serie\n"); + } + return WINMM_MAP_OKMEM; +} + +/************************************************************************** + * MCI_MsgMapper32To16_Destroy [internal] + * + * Helper for MCI_UnMapMsg32ATo16. + */ +static WINMM_MapType MCI_MsgMapper32To16_Destroy(void* ptr, int size16, DWORD map, BOOLEAN kept) +{ + if (ptr) { + void* msg16 = MapSL((SEGPTR)ptr); + void* alloc; + LPBYTE p32, p16; + unsigned nibble; + + UnMapLS( (SEGPTR)ptr ); + if (kept) { + alloc = (char*)msg16 - sizeof(void**); + p32 = *(void**)alloc; + p16 = msg16; + + if (map == 0) { + memcpy(p32, p16, size16); + } else { + while (map & 0xF) { + nibble = map & 0xF; + if (nibble & 0x8) { + memcpy(p32, p16, (nibble & 7) + 1); + p16 += (nibble & 7) + 1; + p32 += (nibble & 7) + 1; + size16 -= (nibble & 7) + 1; + } else { + switch (nibble) { + case 0x1: + *(LPINT)p32 = *(LPINT16)p16; + p16 += sizeof(INT16); + p32 += sizeof(INT); + size16 -= sizeof(INT16); + break; + case 0x2: + *(LPUINT)p32 = *(LPUINT16)p16; + p16 += sizeof(UINT16); + p32 += sizeof(UINT); + size16 -= sizeof(UINT16); + break; + case 0x6: + p16 += sizeof(UINT); + p32 += sizeof(UINT); + size16 -= sizeof(UINT); + break; + case 0x7: + UnMapLS( *(SEGPTR *)p16 ); + p16 += sizeof(SEGPTR); + p32 += sizeof(char*); + size16 -= sizeof(SEGPTR); + break; + default: + FIXME("Unknown nibble for mapping (%x)\n", nibble); + } + } + map >>= 4; + } + if (size16 != 0) /* DEBUG only */ + FIXME("Mismatch between 16 bit struct size and map nibbles serie\n"); + } + } else { + alloc = msg16; + } + + HeapFree( GetProcessHeap(), 0, alloc ); + } + return WINMM_MAP_OK; +} + +/************************************************************************** + * MCI_MapMsg32ATo16 [internal] + * + * Map a 32-A bit MCI message to a 16 bit MCI message. + */ +static WINMM_MapType MCI_MapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD* lParam) +{ + int size; + BOOLEAN keep = FALSE; + DWORD map = 0; + + if (*lParam == 0) + return WINMM_MAP_OK; + + /* FIXME: to add also (with seg/linear modifications to do): + * MCI_LIST, MCI_LOAD, MCI_QUALITY, MCI_RESERVE, MCI_RESTORE, MCI_SAVE + * MCI_SETAUDIO, MCI_SETTUNER, MCI_SETVIDEO + */ + switch (wMsg) { + case MCI_BREAK: + size = sizeof(MCI_BREAK_PARMS); + break; + /* case MCI_CAPTURE */ + case MCI_CLOSE: + case MCI_CLOSE_DRIVER: + case MCI_CONFIGURE: + size = sizeof(MCI_GENERIC_PARMS); + break; + /* case MCI_COPY: */ + case MCI_CUE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_CUE_PARMS); break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_CUE_PARMS); break;*/ FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + /* case MCI_CUT:*/ + case MCI_DELETE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_DELETE_PARMS16); map = 0x0F1111FB; break; + case MCI_DEVTYPE_WAVEFORM_AUDIO:size = sizeof(MCI_WAVE_DELETE_PARMS); break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + /* case MCI_ESCAPE: */ + case MCI_FREEZE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_FREEZE_PARMS); map = 0x0001111B; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS); map = 0x0001111B; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_GETDEVCAPS: + keep = TRUE; + size = sizeof(MCI_GETDEVCAPS_PARMS); + break; + /* case MCI_INDEX: */ + case MCI_INFO: + { + LPMCI_INFO_PARMSA mip32a = (LPMCI_INFO_PARMSA)(*lParam); + LPMCI_INFO_PARMS16 mip16; + + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_INFO_PARMS16); break; + default: size = sizeof(MCI_INFO_PARMS16); break; + } + mip16 = HeapAlloc( GetProcessHeap(), 0, size); + if (mip16) + { + mip16->dwCallback = mip32a->dwCallback; + mip16->lpstrReturn = MapLS( mip32a->lpstrReturn ); + mip16->dwRetSize = mip32a->dwRetSize; + if (uDevType == MCI_DEVTYPE_DIGITAL_VIDEO) { + ((LPMCI_DGV_INFO_PARMS16)mip16)->dwItem = ((LPMCI_DGV_INFO_PARMSA)mip32a)->dwItem; + } + } else { + return WINMM_MAP_NOMEM; + } + *lParam = MapLS(mip16); + } + return WINMM_MAP_OKMEM; + /* case MCI_MARK: */ + /* case MCI_MONITOR: */ + case MCI_OPEN: + case MCI_OPEN_DRIVER: + { + LPMCI_OPEN_PARMSA mop32a = (LPMCI_OPEN_PARMSA)(*lParam); + char* ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPMCI_OPEN_PARMSA) + sizeof(MCI_OPEN_PARMS16) + 2 * sizeof(DWORD)); + LPMCI_OPEN_PARMS16 mop16; + + + if (ptr) { + *(LPMCI_OPEN_PARMSA*)(ptr) = mop32a; + mop16 = (LPMCI_OPEN_PARMS16)(ptr + sizeof(LPMCI_OPEN_PARMSA)); + mop16->dwCallback = mop32a->dwCallback; + mop16->wDeviceID = mop32a->wDeviceID; + if (dwFlags & MCI_OPEN_TYPE) { + if (dwFlags & MCI_OPEN_TYPE_ID) { + /* dword "transparent" value */ + mop16->lpstrDeviceType = (SEGPTR)mop32a->lpstrDeviceType; + } else { + /* string */ + mop16->lpstrDeviceType = MapLS( mop32a->lpstrDeviceType ); + } + } else { + /* nuthin' */ + mop16->lpstrDeviceType = 0; + } + if (dwFlags & MCI_OPEN_ELEMENT) { + if (dwFlags & MCI_OPEN_ELEMENT_ID) { + mop16->lpstrElementName = (SEGPTR)mop32a->lpstrElementName; + } else { + mop16->lpstrElementName = MapLS( mop32a->lpstrElementName ); + } + } else { + mop16->lpstrElementName = 0; + } + if (dwFlags & MCI_OPEN_ALIAS) { + mop16->lpstrAlias = MapLS( mop32a->lpstrAlias ); + } else { + mop16->lpstrAlias = 0; + } + /* copy extended information if any... + * FIXME: this may seg fault if initial structure does not contain them and + * the reads after msip16 fail under LDT limits... + * NOTE: this should be split in two. First pass, while calling MCI_OPEN, and + * should not take care of extended parameters, and should be used by MCI_Open + * to fetch uDevType. When, this is known, the mapping for sending the + * MCI_OPEN_DRIVER shall be done depending on uDevType. + */ + memcpy(mop16 + 1, mop32a + 1, 2 * sizeof(DWORD)); + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_OPEN_PARMSA); + } + return WINMM_MAP_OKMEM; + /* case MCI_PASTE:*/ + case MCI_PAUSE: + size = sizeof(MCI_GENERIC_PARMS); + break; + case MCI_PLAY: + size = sizeof(MCI_PLAY_PARMS); + break; + case MCI_PUT: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS); map = 0x0001111B; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_REALIZE: + size = sizeof(MCI_GENERIC_PARMS); + break; + case MCI_RECORD: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECORD_PARMS16); map = 0x0F1111FB; break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_RECORD_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_RECORD_PARMS); break; + } + break; + case MCI_RESUME: + size = sizeof(MCI_GENERIC_PARMS); + break; + case MCI_SEEK: + switch (uDevType) { + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SEEK_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_SEEK_PARMS); break; + } + break; + case MCI_SET: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_SET_PARMS); break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SET_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + case MCI_DEVTYPE_SEQUENCER: size = sizeof(MCI_SEQ_SET_PARMS); break; + /* FIXME: normally the 16 and 32 bit structures are byte by byte aligned, + * so not doing anything should work... + */ + case MCI_DEVTYPE_WAVEFORM_AUDIO:size = sizeof(MCI_WAVE_SET_PARMS); break; + default: size = sizeof(MCI_SET_PARMS); break; + } + break; + case MCI_SETAUDIO: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_SETAUDIO_PARMS16);map = 0x0000077FF; break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SETAUDIO_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + /* case MCI_SETTIMECODE:*/ + /* case MCI_SIGNAL:*/ + /* case MCI_SOUND:*/ + case MCI_SPIN: + size = sizeof(MCI_SET_PARMS); + break; + case MCI_STATUS: + keep = TRUE; + switch (uDevType) { + /* FIXME: + * don't know if buffer for value is the one passed through lpstrDevice + * or is provided by MCI driver. + * Assuming solution 2: provided by MCI driver, so zeroing on entry + */ + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STATUS_PARMS16); map = 0x0B6FF; break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STATUS_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_STATUS_PARMS); break; + } + break; + case MCI_STEP: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STEP_PARMS); break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STEP_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + case MCI_DEVTYPE_VIDEODISC: size = sizeof(MCI_VD_STEP_PARMS); break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_STOP: + size = sizeof(MCI_SET_PARMS); + break; + case MCI_SYSINFO: + { + LPMCI_SYSINFO_PARMSA msip32a = (LPMCI_SYSINFO_PARMSA)(*lParam); + LPMCI_SYSINFO_PARMS16 msip16; + char* ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPMCI_SYSINFO_PARMSA) + sizeof(MCI_SYSINFO_PARMS16) ); + + if (ptr) { + *(LPMCI_SYSINFO_PARMSA*)(ptr) = msip32a; + msip16 = (LPMCI_SYSINFO_PARMS16)(ptr + sizeof(LPMCI_SYSINFO_PARMSA)); + + msip16->dwCallback = msip32a->dwCallback; + msip16->lpstrReturn = MapLS( msip32a->lpstrReturn ); + msip16->dwRetSize = msip32a->dwRetSize; + msip16->dwNumber = msip32a->dwNumber; + msip16->wDeviceType = msip32a->wDeviceType; + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_SYSINFO_PARMSA); + } + return WINMM_MAP_OKMEM; + /* case MCI_UNDO: */ + case MCI_UNFREEZE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_UPDATE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_UPDATE_PARMS16); map = 0x000B1111B; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_WHERE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; keep = TRUE; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; keep = TRUE; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_WINDOW: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_WINDOW_PARMS16); if (dwFlags & MCI_DGV_WINDOW_TEXT) map = 0x7FB; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_WINDOW_PARMS16); if (dwFlags & MCI_OVLY_WINDOW_TEXT) map = 0x7FB; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case DRV_OPEN: + { + LPMCI_OPEN_DRIVER_PARMSA modp32a = (LPMCI_OPEN_DRIVER_PARMSA)(*lParam); + LPMCI_OPEN_DRIVER_PARMS16 modp16; + char *ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPMCI_OPEN_DRIVER_PARMSA) + sizeof(MCI_OPEN_DRIVER_PARMS16)); + + if (ptr) { + *(LPMCI_OPEN_DRIVER_PARMSA*)(ptr) = modp32a; + modp16 = (LPMCI_OPEN_DRIVER_PARMS16)(ptr + sizeof(LPMCI_OPEN_DRIVER_PARMSA)); + modp16->wDeviceID = modp32a->wDeviceID; + modp16->lpstrParams = MapLS( modp32a->lpstrParams ); + /* other fields are gonna be filled by the driver, don't copy them */ + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_OPEN_DRIVER_PARMSA); + } + return WINMM_MAP_OKMEM; + case DRV_LOAD: + case DRV_ENABLE: + case DRV_CLOSE: + case DRV_DISABLE: + case DRV_FREE: + case DRV_CONFIGURE: + case DRV_QUERYCONFIGURE: + case DRV_INSTALL: + case DRV_REMOVE: + case DRV_EXITSESSION: + case DRV_EXITAPPLICATION: + case DRV_POWER: + return WINMM_MAP_OK; + + default: + WARN("Don't know how to map msg=%s\n", MCI_MessageToString(wMsg)); + return WINMM_MAP_MSGERROR; + } + return MCI_MsgMapper32To16_Create((void**)lParam, size, map, keep); +} + +/************************************************************************** + * MCI_UnMapMsg32ATo16 [internal] + */ +static WINMM_MapType MCI_UnMapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD lParam) +{ + int size = 0; + BOOLEAN kept = FALSE; /* there is no need to compute size when kept is FALSE */ + DWORD map = 0; + + switch (wMsg) { + case MCI_BREAK: + break; + /* case MCI_CAPTURE */ + case MCI_CLOSE: + case MCI_CLOSE_DRIVER: + case MCI_CONFIGURE: + break; + /* case MCI_COPY: */ + case MCI_CUE: + break; + /* case MCI_CUT: */ + case MCI_DELETE: + break; + /* case MCI_ESCAPE: */ + case MCI_FREEZE: + break; + case MCI_GETDEVCAPS: + kept = TRUE; + size = sizeof(MCI_GETDEVCAPS_PARMS); + break; + /* case MCI_INDEX: */ + case MCI_INFO: + { + LPMCI_INFO_PARMS16 mip16 = (LPMCI_INFO_PARMS16)MapSL(lParam); + UnMapLS( lParam ); + UnMapLS( mip16->lpstrReturn ); + HeapFree( GetProcessHeap(), 0, mip16 ); + } + return WINMM_MAP_OK; + /* case MCI_MARK: */ + /* case MCI_MONITOR: */ + case MCI_OPEN: + case MCI_OPEN_DRIVER: + if (lParam) { + LPMCI_OPEN_PARMS16 mop16 = (LPMCI_OPEN_PARMS16)MapSL(lParam); + LPMCI_OPEN_PARMSA mop32a = *(LPMCI_OPEN_PARMSA*)((char*)mop16 - sizeof(LPMCI_OPEN_PARMSA)); + UnMapLS( lParam ); + mop32a->wDeviceID = mop16->wDeviceID; + if ((dwFlags & MCI_OPEN_TYPE) && !(dwFlags & MCI_OPEN_TYPE_ID)) + UnMapLS( mop16->lpstrDeviceType ); + if ((dwFlags & MCI_OPEN_ELEMENT) && !(dwFlags & MCI_OPEN_ELEMENT_ID)) + UnMapLS( mop16->lpstrElementName ); + if (dwFlags & MCI_OPEN_ALIAS) + UnMapLS( mop16->lpstrAlias ); + HeapFree( GetProcessHeap(), 0, (char*)mop16 - sizeof(LPMCI_OPEN_PARMSA) ); + } + return WINMM_MAP_OK; + /* case MCI_PASTE:*/ + case MCI_PAUSE: + break; + case MCI_PLAY: + break; + case MCI_PUT: + break; + case MCI_REALIZE: + break; + case MCI_RECORD: + break; + case MCI_RESUME: + break; + case MCI_SEEK: + break; + case MCI_SET: + break; + case MCI_SETAUDIO: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: map = 0x0000077FF; break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SETAUDIO_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + } + break; + /* case MCI_SETTIMECODE:*/ + /* case MCI_SIGNAL:*/ + /* case MCI_SOUND:*/ + case MCI_SPIN: + break; + case MCI_STATUS: + kept = TRUE; + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: + if (lParam) { + LPMCI_DGV_STATUS_PARMS16 mdsp16 = (LPMCI_DGV_STATUS_PARMS16)MapSL(lParam); + LPMCI_DGV_STATUS_PARMSA mdsp32a = *(LPMCI_DGV_STATUS_PARMSA*)((char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA)); + + UnMapLS( lParam ); + if (mdsp16) { + mdsp32a->dwReturn = mdsp16->dwReturn; + if (dwFlags & MCI_DGV_STATUS_DISKSPACE) { + TRACE("MCI_STATUS (DGV) lpstrDrive=%08lx\n", mdsp16->lpstrDrive); + TRACE("MCI_STATUS (DGV) lpstrDrive=%s\n", (LPSTR)MapSL(mdsp16->lpstrDrive)); + UnMapLS( mdsp16->lpstrDrive ); + } + HeapFree( GetProcessHeap(), 0, (char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA) ); + } else { + return WINMM_MAP_NOMEM; + } + } + return WINMM_MAP_OKMEM; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STATUS_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_STATUS_PARMS); break; + } + break; + case MCI_STEP: + break; + case MCI_STOP: + break; + case MCI_SYSINFO: + if (lParam) { + LPMCI_SYSINFO_PARMS16 msip16 = (LPMCI_SYSINFO_PARMS16)MapSL(lParam); + LPMCI_SYSINFO_PARMSA msip32a = *(LPMCI_SYSINFO_PARMSA*)((char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSA)); + + UnMapLS( lParam ); + if (msip16) { + msip16->dwCallback = msip32a->dwCallback; + UnMapLS( msip16->lpstrReturn ); + HeapFree( GetProcessHeap(), 0, (char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSA) ); + } else { + return WINMM_MAP_NOMEM; + } + } + return WINMM_MAP_OKMEM; + /* case MCI_UNDO: */ + case MCI_UNFREEZE: + break; + case MCI_UPDATE: + break; + case MCI_WHERE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; kept = TRUE; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; kept = TRUE; break; + default: break; + } + break; + case MCI_WINDOW: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_WINDOW_PARMS16); if (dwFlags & MCI_DGV_WINDOW_TEXT) map = 0x7666; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_WINDOW_PARMS16); if (dwFlags & MCI_OVLY_WINDOW_TEXT) map = 0x7666; break; + default: break; + } + /* FIXME: see map function */ + break; + + case DRV_OPEN: + if (lParam) { + LPMCI_OPEN_DRIVER_PARMS16 modp16 = (LPMCI_OPEN_DRIVER_PARMS16)MapSL(lParam); + LPMCI_OPEN_DRIVER_PARMSA modp32a = *(LPMCI_OPEN_DRIVER_PARMSA*)((char*)modp16 - sizeof(LPMCI_OPEN_DRIVER_PARMSA)); + + UnMapLS( lParam ); + modp32a->wCustomCommandTable = modp16->wCustomCommandTable; + modp32a->wType = modp16->wType; + UnMapLS( modp16->lpstrParams ); + HeapFree( GetProcessHeap(), 0, (char *)modp16 - sizeof(LPMCI_OPEN_DRIVER_PARMSA) ); + } + return WINMM_MAP_OK; + case DRV_LOAD: + case DRV_ENABLE: + case DRV_CLOSE: + case DRV_DISABLE: + case DRV_FREE: + case DRV_CONFIGURE: + case DRV_QUERYCONFIGURE: + case DRV_INSTALL: + case DRV_REMOVE: + case DRV_EXITSESSION: + case DRV_EXITAPPLICATION: + case DRV_POWER: + FIXME("This is a hack\n"); + return WINMM_MAP_OK; + default: + FIXME("Map/Unmap internal error on msg=%s\n", MCI_MessageToString(wMsg)); + return WINMM_MAP_MSGERROR; + } + return MCI_MsgMapper32To16_Destroy((void*)lParam, size, map, kept); +} + +void MMDRV_Init16(void) +{ +#define A(_x,_y) MMDRV_InstallMap(_x, \ +MMDRV_##_y##_Map16To32A, MMDRV_##_y##_UnMap16To32A, \ +MMDRV_##_y##_Map32ATo16, MMDRV_##_y##_UnMap32ATo16, \ +MMDRV_##_y##_Callback) + A(MMDRV_AUX, Aux); + A(MMDRV_MIXER, Mixer); + A(MMDRV_MIDIIN, MidiIn); + A(MMDRV_MIDIOUT, MidiOut); + A(MMDRV_WAVEIN, WaveIn); + A(MMDRV_WAVEOUT, WaveOut); +#undef A + + pFnCallMMDrvFunc16 = MMDRV_CallMMDrvFunc16; + pFnLoadMMDrvFunc16 = MMDRV_LoadMMDrvFunc16; + + pFnMciMapMsg16To32A = MCI_MapMsg16To32A; + pFnMciUnMapMsg16To32A = MCI_UnMapMsg16To32A; + pFnMciMapMsg32ATo16 = MCI_MapMsg32ATo16; + pFnMciUnMapMsg32ATo16 = MCI_UnMapMsg32ATo16; +} diff --git a/reactos/lib/winmm/midimap/.cvsignore b/reactos/lib/winmm/midimap/.cvsignore new file mode 100644 index 00000000000..38400f6e478 --- /dev/null +++ b/reactos/lib/winmm/midimap/.cvsignore @@ -0,0 +1,2 @@ +Makefile +midimap.drv.dbg.c diff --git a/reactos/lib/winmm/midimap/Makefile.in b/reactos/lib/winmm/midimap/Makefile.in new file mode 100644 index 00000000000..044c17a4c09 --- /dev/null +++ b/reactos/lib/winmm/midimap/Makefile.in @@ -0,0 +1,13 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = midimap.drv +IMPORTS = winmm user32 advapi32 kernel32 + +C_SRCS = \ + midimap.c + +@MAKE_DLL_RULES@ + +### Dependencies: diff --git a/reactos/lib/winmm/midimap/Makefile.ros-template b/reactos/lib/winmm/midimap/Makefile.ros-template new file mode 100644 index 00000000000..261fd10301a --- /dev/null +++ b/reactos/lib/winmm/midimap/Makefile.ros-template @@ -0,0 +1,23 @@ +# $Id: Makefile.ros-template 11910 2004-12-03 23:37:44Z blight $ + +TARGET_NAME = midimap + +TARGET_OBJECTS = @C_SRCS@ + +TARGET_CFLAGS = @EXTRADEFS@ -D__REACTOS__ + +TARGET_SDKLIBS = @IMPORTS@ winmm.a wine.a wine_uuid.a ntdll.a + +TARGET_BASE = $(TARGET_LIB_BASE_MIDIMAP) + +TARGET_RC_SRCS = @RC_SRCS@ +TARGET_RC_BINSRC = @RC_BINSRC@ +TARGET_RC_BINARIES = @RC_BINARIES@ + +TARGET_EXTENSION = .dll + +default: all + +DEP_OBJECTS = $(TARGET_OBJECTS) + +include $(TOOLS_PATH)/depend.mk diff --git a/reactos/lib/winmm/midimap/makefile b/reactos/lib/winmm/midimap/makefile new file mode 100644 index 00000000000..11941603f41 --- /dev/null +++ b/reactos/lib/winmm/midimap/makefile @@ -0,0 +1,9 @@ +# $Id: makefile 8620 2004-03-10 15:22:45Z silverblade $ + +PATH_TO_TOP = ../../.. + +TARGET_TYPE = winedll + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk diff --git a/reactos/lib/winmm/midimap/midimap.c b/reactos/lib/winmm/midimap/midimap.c new file mode 100644 index 00000000000..014307f8a5d --- /dev/null +++ b/reactos/lib/winmm/midimap/midimap.c @@ -0,0 +1,555 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ +/* + * Wine MIDI mapper driver + * + * Copyright 1999, 2000, 2001 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 + * + * TODO: + * notification has to be implemented + * IDF file loading + */ + +#include +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "mmddk.h" +#include "winreg.h" +#include "wine/debug.h" + +/* + * Here's how Windows stores the midiOut mapping information. + * + * Full form (in HKU) is: + * + * [Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap] 988836060 + * "AutoScheme"=dword:00000000 + * "ConfigureCount"=dword:00000004 + * "CurrentInstrument"="Wine OSS midi" + * "CurrentScheme"="epp" + * "DriverList"="" + * "UseScheme"=dword:00000000 + * + * AutoScheme: ? + * CurrentInstrument: name of midiOut device to use when UseScheme is 0. Wine uses an extension + * of the form #n to link to n'th midiOut device of the system + * CurrentScheme: when UseScheme is non null, it's the scheme to use (see below) + * DriverList: ? + * UseScheme: trigger for simple/complex mapping + * + * A scheme is defined (in HKLM) as: + * + * [System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Schemes\\] + * : one key for each defined scheme (system wide) + * under each one of these keys, there's: + * [...\\\\] + * "Channels"="" + * (the default value of this key also refers to the name of the device). + * + * this defines, for each midiOut device (identified by its index in ), which + * channels have to be mapped onto it. The defines the channels (from 0 to 15) + * will be mapped (mapping occurs for channel if bit is set in + * + * Further mapping information can also be defined in: + * [System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Ports\\\\Instruments\\] + * "Definition"="<.idf file>" + * "FriendlyName"="#for .idx file#" + * "Port"="" + * + * This last part isn't implemented (.idf file support). + */ + +WINE_DEFAULT_DEBUG_CHANNEL(msacm); + +typedef struct tagMIDIOUTPORT +{ + char name[MAXPNAMELEN]; + int loaded; + HMIDIOUT hMidi; + unsigned short uDevID; + LPBYTE lpbPatch; + unsigned int aChn[16]; +} MIDIOUTPORT; + +typedef struct tagMIDIMAPDATA +{ + struct tagMIDIMAPDATA* self; + MIDIOUTPORT* ChannelMap[16]; +} MIDIMAPDATA; + +static MIDIOUTPORT* midiOutPorts; +static unsigned numMidiOutPorts; + +static BOOL MIDIMAP_IsBadData(MIDIMAPDATA* mm) +{ + if (!IsBadReadPtr(mm, sizeof(MIDIMAPDATA)) && mm->self == mm) + return FALSE; + TRACE("Bad midimap data (%p)\n", mm); + return TRUE; +} + +static BOOL MIDIMAP_FindPort(const char* name, unsigned* dev) +{ + for (*dev = 0; *dev < numMidiOutPorts; (*dev)++) + { + TRACE("%s\n", midiOutPorts[*dev].name); + if (strcmp(midiOutPorts[*dev].name, name) == 0) + return TRUE; + } + /* try the form #nnn */ + if (*name == '#' && isdigit(name[1])) + { + *dev = atoi(name + 1); + if (*dev < numMidiOutPorts) + return TRUE; + } + return FALSE; +} + +static BOOL MIDIMAP_LoadSettingsDefault(MIDIMAPDATA* mom, const char* port) +{ + unsigned i, dev = 0; + + if (port != NULL && !MIDIMAP_FindPort(port, &dev)) + { + ERR("Registry glitch: couldn't find midi out (%s)\n", port); + dev = 0; + } + + /* this is necessary when no midi out ports are present */ + if (dev >= numMidiOutPorts) + return FALSE; + /* sets default */ + for (i = 0; i < 16; i++) mom->ChannelMap[i] = &midiOutPorts[dev]; + + return TRUE; +} + +static BOOL MIDIMAP_LoadSettingsScheme(MIDIMAPDATA* mom, const char* scheme) +{ + HKEY hSchemesKey, hKey, hPortKey; + unsigned i, idx, dev; + char buffer[256], port[256]; + DWORD type, size, mask; + + for (i = 0; i < 16; i++) mom->ChannelMap[i] = NULL; + + if (RegOpenKeyA(HKEY_LOCAL_MACHINE, + "System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Schemes", + &hSchemesKey)) + { + return FALSE; + } + if (RegOpenKeyA(hSchemesKey, scheme, &hKey)) + { + RegCloseKey(hSchemesKey); + return FALSE; + } + + for (idx = 0; !RegEnumKeyA(hKey, idx, buffer, sizeof(buffer)); idx++) + { + if (RegOpenKeyA(hKey, buffer, &hPortKey)) continue; + + size = sizeof(port); + if (RegQueryValueExA(hPortKey, NULL, 0, &type, port, &size)) continue; + + if (!MIDIMAP_FindPort(port, &dev)) continue; + + size = sizeof(mask); + if (RegQueryValueExA(hPortKey, "Channels", 0, &type, (void*)&mask, &size)) + continue; + + for (i = 0; i < 16; i++) + { + if (mask & (1 << i)) + { + if (mom->ChannelMap[i]) + ERR("Quirks in registry, channel %u is mapped twice\n", i); + mom->ChannelMap[i] = &midiOutPorts[dev]; + } + } + } + + RegCloseKey(hSchemesKey); + RegCloseKey(hKey); + + return TRUE; +} + +static BOOL MIDIMAP_LoadSettings(MIDIMAPDATA* mom) +{ + HKEY hKey; + BOOL ret; + + if (RegOpenKeyA(HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap", &hKey)) + { + ret = MIDIMAP_LoadSettingsDefault(mom, NULL); + } + else + { + DWORD type, size, out; + char buffer[256]; + + ret = 2; + size = sizeof(out); + if (!RegQueryValueExA(hKey, "UseScheme", 0, &type, (void*)&out, &size) && out) + { + size = sizeof(buffer); + if (!RegQueryValueExA(hKey, "CurrentScheme", 0, &type, buffer, &size)) + { + if (!(ret = MIDIMAP_LoadSettingsScheme(mom, buffer))) + ret = MIDIMAP_LoadSettingsDefault(mom, NULL); + } + else + { + ERR("Wrong registry: UseScheme is active, but no CurrentScheme found\n"); + } + } + if (ret == 2) + { + size = sizeof(buffer); + if (!RegQueryValueExA(hKey, "CurrentInstrument", 0, &type, buffer, &size) && *buffer) + { + ret = MIDIMAP_LoadSettingsDefault(mom, buffer); + } + else + { + ret = MIDIMAP_LoadSettingsDefault(mom, NULL); + } + } + } + RegCloseKey(hKey); + + if (ret && TRACE_ON(msacm)) + { + unsigned i; + + for (i = 0; i < 16; i++) + { + TRACE("chnMap[%2d] => %d\n", + i, mom->ChannelMap[i] ? mom->ChannelMap[i]->uDevID : -1); + } + } + return ret; +} + +static DWORD modOpen(LPDWORD lpdwUser, LPMIDIOPENDESC lpDesc, DWORD dwFlags) +{ + MIDIMAPDATA* mom = HeapAlloc(GetProcessHeap(), 0, sizeof(MIDIMAPDATA)); + + TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags); + + if (!mom) return MMSYSERR_NOMEM; + + if (MIDIMAP_LoadSettings(mom)) + { + *lpdwUser = (DWORD)mom; + mom->self = mom; + + return MMSYSERR_NOERROR; + } + HeapFree(GetProcessHeap(), 0, mom); + return MIDIERR_INVALIDSETUP; +} + +static DWORD modClose(MIDIMAPDATA* mom) +{ + UINT i; + DWORD ret = MMSYSERR_NOERROR; + + if (MIDIMAP_IsBadData(mom)) return MMSYSERR_ERROR; + + for (i = 0; i < 16; i++) + { + DWORD t; + if (mom->ChannelMap[i] && mom->ChannelMap[i]->loaded > 0) + { + t = midiOutClose(mom->ChannelMap[i]->hMidi); + if (t == MMSYSERR_NOERROR) + { + mom->ChannelMap[i]->loaded = 0; + mom->ChannelMap[i]->hMidi = 0; + } + else if (ret == MMSYSERR_NOERROR) + ret = t; + } + } + if (ret == MMSYSERR_NOERROR) + HeapFree(GetProcessHeap(), 0, mom); + return ret; +} + +static DWORD modLongData(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2) +{ + WORD chn; + DWORD ret = MMSYSERR_NOERROR; + MIDIHDR mh; + + if (MIDIMAP_IsBadData(mom)) + return MMSYSERR_ERROR; + + mh = *lpMidiHdr; + for (chn = 0; chn < 16; chn++) + { + if (mom->ChannelMap[chn] && mom->ChannelMap[chn]->loaded > 0) + { + mh.dwFlags = 0; + midiOutPrepareHeader(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh)); + ret = midiOutLongMsg(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh)); + midiOutUnprepareHeader(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh)); + if (ret != MMSYSERR_NOERROR) break; + } + } + return ret; +} + +static DWORD modData(MIDIMAPDATA* mom, DWORD dwParam) +{ + BYTE lb = LOBYTE(LOWORD(dwParam)); + WORD chn = lb & 0x0F; + DWORD ret = MMSYSERR_NOERROR; + + if (MIDIMAP_IsBadData(mom)) + return MMSYSERR_ERROR; + + if (!mom->ChannelMap[chn]) return MMSYSERR_NOERROR; + + switch (lb & 0xF0) + { + case 0x80: + case 0x90: + case 0xA0: + case 0xB0: + case 0xC0: + case 0xD0: + case 0xE0: + if (mom->ChannelMap[chn]->loaded == 0) + { + if (midiOutOpen(&mom->ChannelMap[chn]->hMidi, mom->ChannelMap[chn]->uDevID, + 0L, 0L, CALLBACK_NULL) == MMSYSERR_NOERROR) + mom->ChannelMap[chn]->loaded = 1; + else + mom->ChannelMap[chn]->loaded = -1; + /* FIXME: should load here the IDF midi data... and allow channel and + * patch mappings + */ + } + if (mom->ChannelMap[chn]->loaded > 0) + { + /* change channel */ + dwParam &= ~0x0F; + dwParam |= mom->ChannelMap[chn]->aChn[chn]; + + if ((LOBYTE(LOWORD(dwParam)) & 0xF0) == 0xC0 /* program change */ && + mom->ChannelMap[chn]->lpbPatch) + { + BYTE patch = HIBYTE(LOWORD(dwParam)); + + /* change patch */ + dwParam &= ~0x0000FF00; + dwParam |= mom->ChannelMap[chn]->lpbPatch[patch]; + } + ret = midiOutShortMsg(mom->ChannelMap[chn]->hMidi, dwParam); + } + break; + case 0xF0: + for (chn = 0; chn < 16; chn++) + { + if (mom->ChannelMap[chn]->loaded > 0) + ret = midiOutShortMsg(mom->ChannelMap[chn]->hMidi, dwParam); + } + break; + default: + FIXME("ooch %lu\n", dwParam); + } + + return ret; +} + +static DWORD modPrepare(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2) +{ + if (MIDIMAP_IsBadData(mom)) return MMSYSERR_ERROR; + if (lpMidiHdr->dwFlags & (MHDR_ISSTRM|MHDR_PREPARED)) + return MMSYSERR_INVALPARAM; + + lpMidiHdr->dwFlags |= MHDR_PREPARED; + return MMSYSERR_NOERROR; +} + +static DWORD modUnprepare(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2) +{ + if (MIDIMAP_IsBadData(mom)) return MMSYSERR_ERROR; + if ((lpMidiHdr->dwFlags & MHDR_ISSTRM) || !(lpMidiHdr->dwFlags & MHDR_PREPARED)) + return MMSYSERR_INVALPARAM; + + lpMidiHdr->dwFlags &= ~MHDR_PREPARED; + return MMSYSERR_NOERROR; +} + +static DWORD modGetDevCaps(UINT wDevID, MIDIMAPDATA* mom, LPMIDIOUTCAPSA lpMidiCaps, DWORD size) +{ + lpMidiCaps->wMid = 0x00FF; + lpMidiCaps->wPid = 0x0001; + lpMidiCaps->vDriverVersion = 0x0100; + strcpy(lpMidiCaps->szPname, "Wine midi out mapper"); + lpMidiCaps->wTechnology = MOD_MAPPER; + lpMidiCaps->wVoices = 0; + lpMidiCaps->wNotes = 0; + lpMidiCaps->wChannelMask = 0xFFFF; + lpMidiCaps->dwSupport = 0L; + + return MMSYSERR_NOERROR; +} + +static DWORD modReset(MIDIMAPDATA* mom) +{ + WORD chn; + DWORD ret = MMSYSERR_NOERROR; + + if (MIDIMAP_IsBadData(mom)) + return MMSYSERR_ERROR; + + for (chn = 0; chn < 16; chn++) + { + if (mom->ChannelMap[chn] && mom->ChannelMap[chn]->loaded > 0) + { + ret = midiOutReset(mom->ChannelMap[chn]->hMidi); + if (ret != MMSYSERR_NOERROR) break; + } + } + return ret; +} + +/************************************************************************** + * modMessage (MIDIMAP.@) + */ +DWORD WINAPI MIDIMAP_modMessage(UINT wDevID, UINT wMsg, DWORD dwUser, + DWORD dwParam1, DWORD dwParam2) +{ + TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n", + wDevID, wMsg, dwUser, dwParam1, dwParam2); + + switch (wMsg) + { + case DRVM_INIT: + case DRVM_EXIT: + case DRVM_ENABLE: + case DRVM_DISABLE: + /* FIXME: Pretend this is supported */ + return 0; + + case MODM_OPEN: return modOpen ((LPDWORD)dwUser, (LPMIDIOPENDESC)dwParam1,dwParam2); + case MODM_CLOSE: return modClose ((MIDIMAPDATA*)dwUser); + + case MODM_DATA: return modData ((MIDIMAPDATA*)dwUser, dwParam1); + case MODM_LONGDATA: return modLongData ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, dwParam2); + case MODM_PREPARE: return modPrepare ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, dwParam2); + case MODM_UNPREPARE: return modUnprepare ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, dwParam2); + case MODM_RESET: return modReset ((MIDIMAPDATA*)dwUser); + + case MODM_GETDEVCAPS: return modGetDevCaps (wDevID, (MIDIMAPDATA*)dwUser, (LPMIDIOUTCAPSA)dwParam1,dwParam2); + case MODM_GETNUMDEVS: return 1; + case MODM_GETVOLUME: return MMSYSERR_NOTSUPPORTED; + case MODM_SETVOLUME: return MMSYSERR_NOTSUPPORTED; + default: + FIXME("unknown message %d!\n", wMsg); + } + return MMSYSERR_NOTSUPPORTED; +} + +/*======================================================================* + * Driver part * + *======================================================================*/ + +/************************************************************************** + * MIDIMAP_drvOpen [internal] + */ +static DWORD MIDIMAP_drvOpen(LPSTR str) +{ + MIDIOUTCAPSA moc; + unsigned dev, i; + + if (midiOutPorts) + return 0; + + numMidiOutPorts = midiOutGetNumDevs(); + midiOutPorts = HeapAlloc(GetProcessHeap(), 0, + numMidiOutPorts * sizeof(MIDIOUTPORT)); + for (dev = 0; dev < numMidiOutPorts; dev++) + { + if (midiOutGetDevCapsA(dev, &moc, sizeof(moc)) == 0L) + { + strcpy(midiOutPorts[dev].name, moc.szPname); + midiOutPorts[dev].loaded = 0; + midiOutPorts[dev].hMidi = 0; + midiOutPorts[dev].uDevID = dev; + midiOutPorts[dev].lpbPatch = NULL; + for (i = 0; i < 16; i++) + midiOutPorts[dev].aChn[i] = i; + } + else + { + midiOutPorts[dev].loaded = -1; + } + } + + return 1; +} + +/************************************************************************** + * MIDIMAP_drvClose [internal] + */ +static DWORD MIDIMAP_drvClose(DWORD dwDevID) +{ + if (midiOutPorts) + { + HeapFree(GetProcessHeap(), 0, midiOutPorts); + midiOutPorts = NULL; + return 1; + } + return 0; +} + +/************************************************************************** + * DriverProc (MIDIMAP.@) + */ +LONG CALLBACK MIDIMAP_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, + DWORD dwParam1, DWORD dwParam2) +{ +/* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */ +/* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */ + + switch (wMsg) + { + case DRV_LOAD: return 1; + case DRV_FREE: return 1; + case DRV_OPEN: return MIDIMAP_drvOpen((LPSTR)dwParam1); + case DRV_CLOSE: return MIDIMAP_drvClose(dwDevID); + case DRV_ENABLE: return 1; + case DRV_DISABLE: return 1; + case DRV_QUERYCONFIGURE: return 1; + case DRV_CONFIGURE: MessageBoxA(0, "MIDIMAP MultiMedia Driver !", "OSS Driver", MB_OK); return 1; + case DRV_INSTALL: return DRVCNF_RESTART; + case DRV_REMOVE: return DRVCNF_RESTART; + default: + return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); + } +} diff --git a/reactos/lib/winmm/midimap/midimap.drv.spec b/reactos/lib/winmm/midimap/midimap.drv.spec new file mode 100644 index 00000000000..500d318c9c4 --- /dev/null +++ b/reactos/lib/winmm/midimap/midimap.drv.spec @@ -0,0 +1,2 @@ +@ stdcall DriverProc(long long long long long) MIDIMAP_DriverProc +@ stdcall modMessage(long long long long long) MIDIMAP_modMessage diff --git a/reactos/lib/winmm/midimap/midimap.rc b/reactos/lib/winmm/midimap/midimap.rc new file mode 100644 index 00000000000..3809ca14809 --- /dev/null +++ b/reactos/lib/winmm/midimap/midimap.rc @@ -0,0 +1,7 @@ +/* $Id: midimap.rc 11297 2004-10-16 20:27:43Z gvg $ */ + +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "ReactOS/WINE MIDI Mapper\0" +#define REACTOS_STR_INTERNAL_NAME "midimap\0" +#define REACTOS_STR_ORIGINAL_FILENAME "midimap.drv\0" +#include diff --git a/reactos/lib/winmm/midimap/midimap.spec b/reactos/lib/winmm/midimap/midimap.spec new file mode 100644 index 00000000000..500d318c9c4 --- /dev/null +++ b/reactos/lib/winmm/midimap/midimap.spec @@ -0,0 +1,2 @@ +@ stdcall DriverProc(long long long long long) MIDIMAP_DriverProc +@ stdcall modMessage(long long long long long) MIDIMAP_modMessage diff --git a/reactos/lib/winmm/mmio.c b/reactos/lib/winmm/mmio.c new file mode 100644 index 00000000000..e44af2608bc --- /dev/null +++ b/reactos/lib/winmm/mmio.c @@ -0,0 +1,1389 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ +/* + * MMIO functions + * + * Copyright 1998 Andrew Taylor + * Copyright 1998 Ove Kеven + * Copyright 2000,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 + */ + +/* Still to be done: + * + correct handling of global/local IOProcs (and temporary IOProcs) + * + mode of mmio objects is not used (read vs write vs readwrite) + * + thread safeness + * + 32 A <=> W message mapping + */ + + +#include +#include +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "mmsystem.h" +#include "winemm.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mmio); + +LRESULT (*pFnMmioCallback16)(DWORD,LPMMIOINFO,UINT,LPARAM,LPARAM) /* = NULL */; + +/************************************************************************** + * mmioDosIOProc [internal] + */ +static LRESULT CALLBACK mmioDosIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage, + LPARAM lParam1, LPARAM lParam2) +{ + LRESULT ret = MMSYSERR_NOERROR; + + TRACE("(%p, %X, 0x%lx, 0x%lx);\n", lpmmioinfo, uMessage, lParam1, lParam2); + + switch (uMessage) { + case MMIOM_OPEN: + { + /* Parameters: + * lParam1 = szFileName parameter from mmioOpen + * lParam2 = reserved + * Returns: zero on success, error code on error + * NOTE: lDiskOffset automatically set to zero + */ + LPCSTR szFileName = (LPCSTR)lParam1; + + if (lpmmioinfo->dwFlags & MMIO_GETTEMP) { + FIXME("MMIO_GETTEMP not implemented\n"); + return MMIOERR_CANNOTOPEN; + } + + /* if filename NULL, assume open file handle in adwInfo[0] */ + if (szFileName) { + OFSTRUCT ofs; + lpmmioinfo->adwInfo[0] = (DWORD)OpenFile(szFileName, &ofs, lpmmioinfo->dwFlags & 0xFFFF); + } + if (lpmmioinfo->adwInfo[0] == (DWORD)HFILE_ERROR) + ret = MMIOERR_CANNOTOPEN; + } + break; + + case MMIOM_CLOSE: + /* Parameters: + * lParam1 = wFlags parameter from mmioClose + * lParam2 = unused + * Returns: zero on success, error code on error + */ + if (!(lParam1 & MMIO_FHOPEN)) + _lclose((HFILE)lpmmioinfo->adwInfo[0]); + break; + + case MMIOM_READ: + /* Parameters: + * lParam1 = huge pointer to read buffer + * lParam2 = number of bytes to read + * Returns: number of bytes read, 0 for EOF, -1 for error (error code + * in wErrorRet) + */ + ret = _lread((HFILE)lpmmioinfo->adwInfo[0], (HPSTR)lParam1, (LONG)lParam2); + if (ret != -1) + lpmmioinfo->lDiskOffset += ret; + + break; + + case MMIOM_WRITE: + case MMIOM_WRITEFLUSH: + /* no internal buffering, so WRITEFLUSH handled same as WRITE */ + + /* Parameters: + * lParam1 = huge pointer to write buffer + * lParam2 = number of bytes to write + * Returns: number of bytes written, -1 for error (error code in + * wErrorRet) + */ + ret = _hwrite((HFILE)lpmmioinfo->adwInfo[0], (HPSTR)lParam1, (LONG)lParam2); + if (ret != -1) + lpmmioinfo->lDiskOffset += ret; + break; + + case MMIOM_SEEK: + /* Parameters: + * lParam1 = new position + * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END) + * Returns: new file postion, -1 on error + */ + ret = _llseek((HFILE)lpmmioinfo->adwInfo[0], (LONG)lParam1, (LONG)lParam2); + if (ret != -1) + lpmmioinfo->lDiskOffset = ret; + return ret; + + case MMIOM_RENAME: + /* Parameters: + * lParam1 = old name + * lParam2 = new name + * Returns: zero on success, non-zero on failure + */ + if (!MoveFileA((const char*)lParam1, (const char*)lParam2)) + ret = MMIOERR_FILENOTFOUND; + break; + + default: + FIXME("unexpected message %u\n", uMessage); + return 0; + } + + return ret; +} + +/************************************************************************** + * mmioMemIOProc [internal] + */ +static LRESULT CALLBACK mmioMemIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage, + LPARAM lParam1, LPARAM lParam2) +{ + TRACE("(%p,0x%04x,0x%08lx,0x%08lx)\n", lpmmioinfo, uMessage, lParam1, lParam2); + + switch (uMessage) { + + case MMIOM_OPEN: + /* Parameters: + * lParam1 = filename (must be NULL) + * lParam2 = reserved + * Returns: zero on success, error code on error + * NOTE: lDiskOffset automatically set to zero + */ + /* FIXME: io proc shouldn't change it */ + if (!(lpmmioinfo->dwFlags & MMIO_CREATE)) + lpmmioinfo->pchEndRead = lpmmioinfo->pchEndWrite; + lpmmioinfo->adwInfo[0] = HFILE_ERROR; + return 0; + + case MMIOM_CLOSE: + /* Parameters: + * lParam1 = wFlags parameter from mmioClose + * lParam2 = unused + * Returns: zero on success, error code on error + */ + return 0; + + case MMIOM_READ: + /* Parameters: + * lParam1 = huge pointer to read buffer + * lParam2 = number of bytes to read + * Returns: number of bytes read, 0 for EOF, -1 for error (error code + * in wErrorRet) + * NOTE: lDiskOffset should be updated + */ + FIXME("MMIOM_READ on memory files should not occur, buffer may be lost!\n"); + return 0; + + case MMIOM_WRITE: + case MMIOM_WRITEFLUSH: + /* no internal buffering, so WRITEFLUSH handled same as WRITE */ + + /* Parameters: + * lParam1 = huge pointer to write buffer + * lParam2 = number of bytes to write + * Returns: number of bytes written, -1 for error (error code in + * wErrorRet) + * NOTE: lDiskOffset should be updated + */ + FIXME("MMIOM_WRITE on memory files should not occur, buffer may be lost!\n"); + return 0; + + case MMIOM_SEEK: + /* Parameters: + * lParam1 = new position + * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END) + * Returns: new file postion, -1 on error + * NOTE: lDiskOffset should be updated + */ + FIXME("MMIOM_SEEK on memory files should not occur, buffer may be lost!\n"); + return -1; + + default: + FIXME("unexpected message %u\n", uMessage); + return 0; + } + + return 0; +} + +/* This array will be the entire list for most apps + * Note that temporary ioProcs will be stored with a 0 fourCC code + */ + +static struct IOProcList defaultProcs[] = { + {&defaultProcs[1], FOURCC_DOS, (LPMMIOPROC)mmioDosIOProc, MMIO_PROC_32A, 0}, + {NULL, FOURCC_MEM, (LPMMIOPROC)mmioMemIOProc, MMIO_PROC_32A, 0}, +}; + +static struct IOProcList* pIOProcListAnchor = &defaultProcs[0]; + +/**************************************************************** + * MMIO_FindProcNode [INTERNAL] + * + * Finds the ProcList node associated with a given FOURCC code. + */ +static struct IOProcList* MMIO_FindProcNode(FOURCC fccIOProc) +{ + struct IOProcList* pListNode; + + for (pListNode = pIOProcListAnchor; pListNode; pListNode = pListNode->pNext) { + if (pListNode->fourCC == fccIOProc) { + return pListNode; + } + } + return NULL; +} + +/**************************************************************** + * MMIO_InstallIOProc [INTERNAL] + */ +LPMMIOPROC MMIO_InstallIOProc(FOURCC fccIOProc, LPMMIOPROC pIOProc, + DWORD dwFlags, enum mmioProcType type) +{ + LPMMIOPROC lpProc = NULL; + struct IOProcList* pListNode; + struct IOProcList** ppListNode; + + TRACE("(%08lx, %p, %08lX, %i)\n", fccIOProc, pIOProc, dwFlags, type); + + if (dwFlags & MMIO_GLOBALPROC) + FIXME("Global procedures not implemented\n"); + + /* just handle the known procedures for now */ + switch (dwFlags & (MMIO_INSTALLPROC|MMIO_REMOVEPROC|MMIO_FINDPROC)) { + case MMIO_INSTALLPROC: + /* Create new entry for the IOProc list */ + pListNode = HeapAlloc(GetProcessHeap(), 0, sizeof(*pListNode)); + if (pListNode) { + /* Fill in this node */ + pListNode->fourCC = fccIOProc; + pListNode->pIOProc = pIOProc; + pListNode->type = type; + pListNode->count = 0; + + /* Stick it on the end of the list */ + pListNode->pNext = pIOProcListAnchor; + pIOProcListAnchor = pListNode; + + /* Return this IOProc - that's how the caller knows we succeeded */ + lpProc = pIOProc; + } + break; + + case MMIO_REMOVEPROC: + /* + * Search for the node that we're trying to remove + * We search for a matching fourCC code if it's non null, or the proc + * address otherwise + * note that this method won't find the first item on the list, but + * since the first two items on this list are ones we won't + * let the user delete anyway, that's okay + */ + ppListNode = &pIOProcListAnchor; + while ((*ppListNode) && + ((fccIOProc != 0) ? + (*ppListNode)->fourCC != fccIOProc : + (*ppListNode)->pIOProc != pIOProc)) + ppListNode = &((*ppListNode)->pNext); + + if (*ppListNode) { /* found it */ + /* FIXME: what should be done if an open mmio object uses this proc ? + * shall we return an error, nuke the mmio object ? + */ + if ((*ppListNode)->count) { + ERR("Cannot remove a mmIOProc while in use\n"); + break; + } + /* remove it, but only if it isn't builtin */ + if ((*ppListNode) >= defaultProcs && + (*ppListNode) < defaultProcs + sizeof(defaultProcs)) { + WARN("Tried to remove built-in mmio proc. Skipping\n"); + } else { + /* Okay, nuke it */ + struct IOProcList* ptmpNode = *ppListNode; + lpProc = (*ppListNode)->pIOProc; + *ppListNode = (*ppListNode)->pNext; + HeapFree(GetProcessHeap(), 0, ptmpNode); + } + } + break; + + case MMIO_FINDPROC: + if ((pListNode = MMIO_FindProcNode(fccIOProc))) { + lpProc = pListNode->pIOProc; + } + break; + } + + return lpProc; +} + +/**************************************************************** + * send_message [INTERNAL] + */ +static LRESULT send_message(struct IOProcList* ioProc, LPMMIOINFO mmioinfo, + DWORD wMsg, LPARAM lParam1, + LPARAM lParam2, enum mmioProcType type) +{ + LRESULT result = MMSYSERR_ERROR; + LPARAM lp1 = lParam1, lp2 = lParam2; + + if (!ioProc) { + ERR("brrr\n"); + result = MMSYSERR_INVALPARAM; + } + + switch (ioProc->type) { + case MMIO_PROC_16: + if (pFnMmioCallback16) + result = pFnMmioCallback16((DWORD)ioProc->pIOProc, + mmioinfo, wMsg, lp1, lp2); + break; + case MMIO_PROC_32A: + case MMIO_PROC_32W: + if (ioProc->type != type) { + /* map (lParam1, lParam2) into (lp1, lp2) 32 A<=>W */ + FIXME("NIY 32 A<=>W mapping\n"); + } + result = (ioProc->pIOProc)((LPSTR)mmioinfo, wMsg, lp1, lp2); + +#if 0 + if (ioProc->type != type) { + /* unmap (lParam1, lParam2) into (lp1, lp2) 32 A<=>W */ + } +#endif + break; + default: + FIXME("Internal error\n"); + } + + return result; +} + +/************************************************************************** + * MMIO_ParseExtA [internal] + * + * Parses a filename for the extension. + * + * RETURNS + * The FOURCC code for the extension if found, else 0. + */ +static FOURCC MMIO_ParseExtA(LPCSTR szFileName) +{ + /* Filenames are of the form file.ext{+ABC} + For now, we take the last '+' if present */ + + FOURCC ret = 0; + + /* Note that ext{Start,End} point to the . and + respectively */ + LPSTR extEnd; + LPSTR extStart; + + TRACE("(%s)\n", debugstr_a(szFileName)); + + if (!szFileName) + return ret; + + /* Find the last '.' */ + extStart = strrchr(szFileName,'.'); + + if (!extStart) { + ERR("No . in szFileName: %s\n", debugstr_a(szFileName)); + } else { + CHAR ext[5]; + + /* Find the '+' afterwards */ + extEnd = strchr(extStart,'+'); + if (extEnd) { + + if (extEnd - extStart - 1 > 4) + WARN("Extension length > 4\n"); + lstrcpynA(ext, extStart + 1, min(extEnd-extStart,5)); + + } else { + /* No + so just an extension */ + if (strlen(extStart) > 4) { + WARN("Extension length > 4\n"); + } + lstrcpynA(ext, extStart + 1, 5); + } + TRACE("Got extension: %s\n", debugstr_a(ext)); + + /* FOURCC codes identifying file-extensions must be uppercase */ + ret = mmioStringToFOURCCA(ext, MMIO_TOUPPER); + } + return ret; +} + +/************************************************************************** + * MMIO_Get [internal] + * + * Retrieves the mmio object from current process + */ +LPWINE_MMIO MMIO_Get(HMMIO h) +{ + LPWINE_MMIO wm = NULL; + + EnterCriticalSection(&WINMM_IData->cs); + for (wm = WINMM_IData->lpMMIO; wm; wm = wm->lpNext) { + if (wm->info.hmmio == h) + break; + } + LeaveCriticalSection(&WINMM_IData->cs); + return wm; +} + +/************************************************************************** + * MMIO_Create [internal] + * + * Creates an internal representation for a mmio instance + */ +static LPWINE_MMIO MMIO_Create(void) +{ + static WORD MMIO_counter = 0; + LPWINE_MMIO wm; + + wm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MMIO)); + if (wm) { + EnterCriticalSection(&WINMM_IData->cs); + /* lookup next unallocated WORD handle, with a non NULL value */ + while (++MMIO_counter == 0 || MMIO_Get((HMMIO)(ULONG_PTR)MMIO_counter)); + wm->info.hmmio = (HMMIO)(ULONG_PTR)MMIO_counter; + wm->lpNext = WINMM_IData->lpMMIO; + WINMM_IData->lpMMIO = wm; + LeaveCriticalSection(&WINMM_IData->cs); + } + return wm; +} + +/************************************************************************** + * MMIO_Destroy [internal] + *- + * Destroys an internal representation for a mmio instance + */ +static BOOL MMIO_Destroy(LPWINE_MMIO wm) +{ + LPWINE_MMIO* m; + + EnterCriticalSection(&WINMM_IData->cs); + /* search for the matching one... */ + m = &(WINMM_IData->lpMMIO); + while (*m && *m != wm) m = &(*m)->lpNext; + /* ...and destroy */ + if (*m) { + *m = (*m)->lpNext; + HeapFree(GetProcessHeap(), 0, wm); + wm = NULL; + } + LeaveCriticalSection(&WINMM_IData->cs); + return wm ? FALSE : TRUE; +} + +/**************************************************************** + * MMIO_Flush [INTERNAL] + */ +static MMRESULT MMIO_Flush(WINE_MMIO* wm, UINT uFlags) +{ + if (wm->info.cchBuffer && (wm->info.fccIOProc != FOURCC_MEM)) { + /* not quite sure what to do here, but I'll guess */ + if (wm->info.dwFlags & MMIO_DIRTY) { + /* FIXME: error handling */ + send_message(wm->ioProc, &wm->info, MMIOM_SEEK, + wm->info.lBufOffset, SEEK_SET, MMIO_PROC_32A); + send_message(wm->ioProc, &wm->info, MMIOM_WRITE, + (LPARAM)wm->info.pchBuffer, + wm->info.pchNext - wm->info.pchBuffer, MMIO_PROC_32A); + } + if (uFlags & MMIO_EMPTYBUF) + wm->info.pchNext = wm->info.pchEndRead = wm->info.pchBuffer; + } + wm->info.dwFlags &= ~MMIO_DIRTY; + + return MMSYSERR_NOERROR; +} + +/*************************************************************************** + * MMIO_GrabNextBuffer [INTERNAL] + */ +static LONG MMIO_GrabNextBuffer(LPWINE_MMIO wm, int for_read) +{ + LONG size = wm->info.cchBuffer; + + TRACE("bo=%lx do=%lx of=%lx\n", + wm->info.lBufOffset, wm->info.lDiskOffset, + send_message(wm->ioProc, &wm->info, MMIOM_SEEK, 0, SEEK_CUR, MMIO_PROC_32A)); + + wm->info.lBufOffset = wm->info.lDiskOffset; + wm->info.pchNext = wm->info.pchBuffer; + wm->info.pchEndRead = wm->info.pchBuffer; + wm->info.pchEndWrite = wm->info.pchBuffer + wm->info.cchBuffer; + + wm->bBufferLoaded = TRUE; + if (for_read) { + size = send_message(wm->ioProc, &wm->info, MMIOM_READ, + (LPARAM)wm->info.pchBuffer, size, MMIO_PROC_32A); + if (size > 0) + wm->info.pchEndRead += size; + else + wm->bBufferLoaded = FALSE; + } + + return size; +} + +/*************************************************************************** + * MMIO_SetBuffer [INTERNAL] + */ +static MMRESULT MMIO_SetBuffer(WINE_MMIO* wm, void* pchBuffer, LONG cchBuffer, + UINT uFlags) +{ + TRACE("(%p %p %ld %u)\n", wm, pchBuffer, cchBuffer, uFlags); + + if (uFlags) return MMSYSERR_INVALPARAM; + if (cchBuffer > 0xFFFF) + WARN("Untested handling of huge mmio buffers (%ld >= 64k)\n", cchBuffer); + + if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR) + return MMIOERR_CANNOTWRITE; + + /* free previous buffer if allocated */ + if (wm->info.dwFlags & MMIO_ALLOCBUF) { + HeapFree(GetProcessHeap(), 0, wm->info.pchBuffer); + wm->info.pchBuffer = NULL; + wm->info.dwFlags &= ~MMIO_ALLOCBUF; + } + + if (pchBuffer) { + wm->info.pchBuffer = pchBuffer; + } else if (cchBuffer) { + if (!(wm->info.pchBuffer = HeapAlloc(GetProcessHeap(), 0, cchBuffer))) + return MMIOERR_OUTOFMEMORY; + wm->info.dwFlags |= MMIO_ALLOCBUF; + } else { + wm->info.pchBuffer = NULL; + } + + wm->info.cchBuffer = cchBuffer; + wm->info.pchNext = wm->info.pchBuffer; + wm->info.pchEndRead = wm->info.pchBuffer; + wm->info.pchEndWrite = wm->info.pchBuffer + cchBuffer; + wm->info.lBufOffset = 0; + wm->bBufferLoaded = FALSE; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * MMIO_Open [internal] + */ +HMMIO MMIO_Open(LPSTR szFileName, MMIOINFO* refmminfo, DWORD dwOpenFlags, + enum mmioProcType type) +{ + LPWINE_MMIO wm; + MMIOINFO mmioinfo; + + TRACE("('%s', %p, %08lX, %d);\n", szFileName, refmminfo, dwOpenFlags, type); + + if (!refmminfo) { + refmminfo = &mmioinfo; + + mmioinfo.fccIOProc = 0; + mmioinfo.pIOProc = NULL; + mmioinfo.pchBuffer = NULL; + mmioinfo.cchBuffer = 0; + type = MMIO_PROC_32A; + } + + if (dwOpenFlags & (MMIO_PARSE|MMIO_EXIST)) { + char buffer[MAX_PATH]; + + if (GetFullPathNameA(szFileName, sizeof(buffer), buffer, NULL) >= sizeof(buffer)) + return (HMMIO)FALSE; + if ((dwOpenFlags & MMIO_EXIST) && (GetFileAttributesA(buffer) == INVALID_FILE_ATTRIBUTES)) + return (HMMIO)FALSE; + strcpy(szFileName, buffer); + return (HMMIO)TRUE; + } + + if ((wm = MMIO_Create()) == NULL) + return 0; + + /* If both params are NULL, then parse the file name if available */ + if (refmminfo->fccIOProc == 0 && refmminfo->pIOProc == NULL) { + wm->info.fccIOProc = MMIO_ParseExtA(szFileName); + /* Handle any unhandled/error case. Assume DOS file */ + if (wm->info.fccIOProc == 0) + wm->info.fccIOProc = FOURCC_DOS; + if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) { + /* If not found, retry with FOURCC_DOS */ + wm->info.fccIOProc = FOURCC_DOS; + if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) + goto error2; + } + wm->bTmpIOProc = FALSE; + } + /* if just the four character code is present, look up IO proc */ + else if (refmminfo->pIOProc == NULL) { + wm->info.fccIOProc = refmminfo->fccIOProc; + if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2; + wm->bTmpIOProc = FALSE; + } + /* if IO proc specified, use it and specified four character code */ + else { + wm->info.fccIOProc = refmminfo->fccIOProc; + MMIO_InstallIOProc(wm->info.fccIOProc, refmminfo->pIOProc, + MMIO_INSTALLPROC, type); + if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2; + assert(wm->ioProc->pIOProc == refmminfo->pIOProc); + wm->bTmpIOProc = TRUE; + } + + wm->bBufferLoaded = FALSE; + wm->ioProc->count++; + + if (dwOpenFlags & MMIO_ALLOCBUF) { + if ((refmminfo->wErrorRet = MMIO_SetBuffer(wm, NULL, MMIO_DEFAULTBUFFER, 0))) + goto error1; + } else if (wm->info.fccIOProc == FOURCC_MEM) { + refmminfo->wErrorRet = MMIO_SetBuffer(wm, refmminfo->pchBuffer, refmminfo->cchBuffer, 0); + if (refmminfo->wErrorRet != MMSYSERR_NOERROR) + goto error1; + wm->bBufferLoaded = TRUE; + } /* else => unbuffered, wm->info.pchBuffer == NULL */ + + /* see mmioDosIOProc for that one */ + wm->info.adwInfo[0] = refmminfo->adwInfo[0]; + wm->info.dwFlags = dwOpenFlags; + + /* call IO proc to actually open file */ + refmminfo->wErrorRet = send_message(wm->ioProc, &wm->info, MMIOM_OPEN, + (LPARAM)szFileName, 0, MMIO_PROC_32A); + + /* grab file size, when possible */ + wm->dwFileSize = GetFileSize((HANDLE)wm->info.adwInfo[0], NULL); + + if (refmminfo->wErrorRet == 0) + return wm->info.hmmio; + error1: + if (wm->ioProc) wm->ioProc->count--; + error2: + MMIO_Destroy(wm); + return 0; +} + +/************************************************************************** + * mmioOpenW [WINMM.@] + */ +HMMIO WINAPI mmioOpenW(LPWSTR szFileName, MMIOINFO* lpmmioinfo, + DWORD dwOpenFlags) +{ + HMMIO ret; + LPSTR szFn = NULL; + + if (szFileName) + { + INT len = WideCharToMultiByte( CP_ACP, 0, szFileName, -1, NULL, 0, NULL, NULL ); + szFn = HeapAlloc( GetProcessHeap(), 0, len ); + if (!szFn) return (HMMIO)NULL; + WideCharToMultiByte( CP_ACP, 0, szFileName, -1, szFn, len, NULL, NULL ); + } + + ret = MMIO_Open(szFn, lpmmioinfo, dwOpenFlags, MMIO_PROC_32W); + + HeapFree(GetProcessHeap(), 0, szFn); + return ret; +} + +/************************************************************************** + * mmioOpenA [WINMM.@] + */ +HMMIO WINAPI mmioOpenA(LPSTR szFileName, MMIOINFO* lpmmioinfo, + DWORD dwOpenFlags) +{ + return MMIO_Open(szFileName, lpmmioinfo, dwOpenFlags, MMIO_PROC_32A); +} + +/************************************************************************** + * mmioClose [WINMM.@] + */ +MMRESULT WINAPI mmioClose(HMMIO hmmio, UINT uFlags) +{ + LPWINE_MMIO wm; + MMRESULT result; + + TRACE("(%p, %04X);\n", hmmio, uFlags); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + if ((result = MMIO_Flush(wm, 0)) != MMSYSERR_NOERROR) + return result; + + result = send_message(wm->ioProc, &wm->info, MMIOM_CLOSE, + uFlags, 0, MMIO_PROC_32A); + + MMIO_SetBuffer(wm, NULL, 0, 0); + + wm->ioProc->count--; + + if (wm->bTmpIOProc) + MMIO_InstallIOProc(wm->info.fccIOProc, wm->ioProc->pIOProc, + MMIO_REMOVEPROC, wm->ioProc->type); + + MMIO_Destroy(wm); + + return result; +} + +/************************************************************************** + * mmioRead [WINMM.@] + */ +LONG WINAPI mmioRead(HMMIO hmmio, HPSTR pch, LONG cch) +{ + LPWINE_MMIO wm; + LONG count; + + TRACE("(%p, %p, %ld);\n", hmmio, pch, cch); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return -1; + + /* unbuffered case first */ + if (!wm->info.pchBuffer) + return send_message(wm->ioProc, &wm->info, MMIOM_READ, + (LPARAM)pch, cch, MMIO_PROC_32A); + + /* first try from current buffer */ + if (wm->info.pchNext != wm->info.pchEndRead) { + count = wm->info.pchEndRead - wm->info.pchNext; + if (count > cch || count < 0) count = cch; + memcpy(pch, wm->info.pchNext, count); + wm->info.pchNext += count; + pch += count; + cch -= count; + } else + count = 0; + + if (cch && (wm->info.fccIOProc != FOURCC_MEM)) { + assert(wm->info.cchBuffer); + + while (cch) { + LONG size; + + size = MMIO_GrabNextBuffer(wm, TRUE); + if (size <= 0) break; + if (size > cch) size = cch; + memcpy(pch, wm->info.pchBuffer, size); + wm->info.pchNext += size; + pch += size; + cch -= size; + count += size; + } + } + + TRACE("count=%ld\n", count); + return count; +} + +/************************************************************************** + * mmioWrite [WINMM.@] + */ +LONG WINAPI mmioWrite(HMMIO hmmio, HPCSTR pch, LONG cch) +{ + LPWINE_MMIO wm; + LONG count; + + TRACE("(%p, %p, %ld);\n", hmmio, pch, cch); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return -1; + + if (wm->info.cchBuffer) { + LONG bytesW = 0; + + count = 0; + while (cch) { + if (wm->info.pchNext != wm->info.pchEndWrite) { + count = wm->info.pchEndWrite - wm->info.pchNext; + if (count > cch || count < 0) count = cch; + memcpy(wm->info.pchNext, pch, count); + wm->info.pchNext += count; + pch += count; + cch -= count; + bytesW += count; + wm->info.dwFlags |= MMIO_DIRTY; + } else { + if (wm->info.fccIOProc == FOURCC_MEM) { + if (wm->info.adwInfo[0]) { + /* from where would we get the memory handle? */ + FIXME("memory file expansion not implemented!\n"); + break; + } else break; + } + } + + if (wm->info.pchNext == wm->info.pchEndWrite) + { + MMIO_Flush(wm, MMIO_EMPTYBUF); + MMIO_GrabNextBuffer(wm, FALSE); + } + else break; + } + count = bytesW; + } else { + count = send_message(wm->ioProc, &wm->info, MMIOM_WRITE, + (LPARAM)pch, cch, MMIO_PROC_32A); + wm->info.lBufOffset = wm->info.lDiskOffset; + } + + TRACE("bytes written=%ld\n", count); + return count; +} + +/************************************************************************** + * mmioSeek [WINMM.@] + */ +LONG WINAPI mmioSeek(HMMIO hmmio, LONG lOffset, INT iOrigin) +{ + LPWINE_MMIO wm; + LONG offset; + + TRACE("(%p, %08lX, %d);\n", hmmio, lOffset, iOrigin); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + /* not buffered, direct seek on file */ + if (!wm->info.pchBuffer) + return send_message(wm->ioProc, &wm->info, MMIOM_SEEK, + lOffset, iOrigin, MMIO_PROC_32A); + + switch (iOrigin) { + case SEEK_SET: + offset = lOffset; + break; + case SEEK_CUR: + offset = wm->info.lBufOffset + (wm->info.pchNext - wm->info.pchBuffer) + lOffset; + break; + case SEEK_END: + offset = ((wm->info.fccIOProc == FOURCC_MEM)? wm->info.cchBuffer : wm->dwFileSize) - lOffset; + break; + default: + return -1; + } + + if (offset && offset >= wm->dwFileSize && wm->info.fccIOProc != FOURCC_MEM) { + /* should check that write mode exists */ + if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR) + return -1; + wm->info.lBufOffset = offset; + wm->info.pchEndRead = wm->info.pchBuffer; + wm->info.pchEndWrite = wm->info.pchBuffer + wm->info.cchBuffer; + if ((wm->info.dwFlags & MMIO_RWMODE) == MMIO_READ) { + wm->info.lDiskOffset = wm->dwFileSize; + } + } else if ((wm->info.cchBuffer > 0) && + ((offset < wm->info.lBufOffset) || + (offset >= wm->info.lBufOffset + wm->info.cchBuffer) || + !wm->bBufferLoaded)) { + /* stay in same buffer ? */ + /* some memory mapped buffers are defined with -1 as a size */ + + /* condition to change buffer */ + if ((wm->info.fccIOProc == FOURCC_MEM) || + MMIO_Flush(wm, 0) != MMSYSERR_NOERROR || + /* this also sets the wm->info.lDiskOffset field */ + send_message(wm->ioProc, &wm->info, MMIOM_SEEK, + (offset / wm->info.cchBuffer) * wm->info.cchBuffer, + SEEK_SET, MMIO_PROC_32A) == -1) + return -1; + MMIO_GrabNextBuffer(wm, TRUE); + } + + wm->info.pchNext = wm->info.pchBuffer + (offset - wm->info.lBufOffset); + + TRACE("=> %ld\n", offset); + return offset; +} + +/************************************************************************** + * mmioGetInfo [WINMM.@] + */ +MMRESULT WINAPI mmioGetInfo(HMMIO hmmio, MMIOINFO* lpmmioinfo, UINT uFlags) +{ + LPWINE_MMIO wm; + + TRACE("(%p,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + memcpy(lpmmioinfo, &wm->info, sizeof(MMIOINFO)); + /* don't expose 16 bit ioproc:s */ + if (wm->ioProc->type != MMIO_PROC_16) + lpmmioinfo->pIOProc = wm->ioProc->pIOProc; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioSetInfo [WINMM.@] + */ +MMRESULT WINAPI mmioSetInfo(HMMIO hmmio, const MMIOINFO* lpmmioinfo, UINT uFlags) +{ + LPWINE_MMIO wm; + + TRACE("(%p,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + /* check pointers coherence */ + if (lpmmioinfo->pchNext < wm->info.pchBuffer || + lpmmioinfo->pchNext > wm->info.pchBuffer + wm->info.cchBuffer || + lpmmioinfo->pchEndRead < wm->info.pchBuffer || + lpmmioinfo->pchEndRead > wm->info.pchBuffer + wm->info.cchBuffer || + lpmmioinfo->pchEndWrite < wm->info.pchBuffer || + lpmmioinfo->pchEndWrite > wm->info.pchBuffer + wm->info.cchBuffer) + return MMSYSERR_INVALPARAM; + + wm->info.pchNext = lpmmioinfo->pchNext; + wm->info.pchEndRead = lpmmioinfo->pchEndRead; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** +* mmioSetBuffer [WINMM.@] +*/ +MMRESULT WINAPI mmioSetBuffer(HMMIO hmmio, LPSTR pchBuffer, LONG cchBuffer, UINT uFlags) +{ + LPWINE_MMIO wm; + + TRACE("(hmmio=%p, pchBuf=%p, cchBuf=%ld, uFlags=%#08x)\n", + hmmio, pchBuffer, cchBuffer, uFlags); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMIO_SetBuffer(wm, pchBuffer, cchBuffer, uFlags); +} + +/************************************************************************** + * mmioFlush [WINMM.@] + */ +MMRESULT WINAPI mmioFlush(HMMIO hmmio, UINT uFlags) +{ + LPWINE_MMIO wm; + + TRACE("(%p, %04X)\n", hmmio, uFlags); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMIO_Flush(wm, uFlags); +} + +/************************************************************************** + * mmioAdvance [WINMM.@] + */ +MMRESULT WINAPI mmioAdvance(HMMIO hmmio, MMIOINFO* lpmmioinfo, UINT uFlags) +{ + LPWINE_MMIO wm; + + TRACE("hmmio=%p, lpmmioinfo=%p, uFlags=%04X\n", hmmio, lpmmioinfo, uFlags); + + /* NOTE: mmioAdvance16 heavily relies on parameters from lpmmioinfo we're using + * here. be sure if you change something here to check mmioAdvance16 as well + */ + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + if (!wm->info.cchBuffer) + return MMIOERR_UNBUFFERED; + + if (uFlags != MMIO_READ && uFlags != MMIO_WRITE) + return MMSYSERR_INVALPARAM; + + if (uFlags == MMIO_WRITE && (lpmmioinfo->dwFlags & MMIO_DIRTY)) + { + send_message(wm->ioProc, &wm->info, MMIOM_SEEK, + lpmmioinfo->lBufOffset, SEEK_SET, MMIO_PROC_32A); + send_message(wm->ioProc, &wm->info, MMIOM_WRITE, + (LPARAM)lpmmioinfo->pchBuffer, + lpmmioinfo->pchNext - lpmmioinfo->pchBuffer, MMIO_PROC_32A); + lpmmioinfo->dwFlags &= ~MMIO_DIRTY; + } + if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR) + return MMIOERR_CANNOTWRITE; + + if (lpmmioinfo) { + wm->dwFileSize = max(wm->dwFileSize, lpmmioinfo->lBufOffset + + (lpmmioinfo->pchNext - lpmmioinfo->pchBuffer)); + } + MMIO_GrabNextBuffer(wm, uFlags == MMIO_READ); + + if (lpmmioinfo) { + lpmmioinfo->pchNext = lpmmioinfo->pchBuffer; + lpmmioinfo->pchEndRead = lpmmioinfo->pchBuffer + + (wm->info.pchEndRead - wm->info.pchBuffer); + lpmmioinfo->pchEndWrite = lpmmioinfo->pchBuffer + + (wm->info.pchEndWrite - wm->info.pchBuffer); + lpmmioinfo->lDiskOffset = wm->info.lDiskOffset; + lpmmioinfo->lBufOffset = wm->info.lBufOffset; + } + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioStringToFOURCCA [WINMM.@] + */ +FOURCC WINAPI mmioStringToFOURCCA(LPCSTR sz, UINT uFlags) +{ + CHAR cc[4]; + int i = 0; + + for (i = 0; i < 4 && sz[i]; i++) { + if (uFlags & MMIO_TOUPPER) { + cc[i] = toupper(sz[i]); + } else { + cc[i] = sz[i]; + } + } + + /* Pad with spaces */ + while (i < 4) cc[i++] = ' '; + + TRACE("Got '%.4s'\n",cc); + return mmioFOURCC(cc[0],cc[1],cc[2],cc[3]); +} + +/************************************************************************** + * mmioStringToFOURCCW [WINMM.@] + */ +FOURCC WINAPI mmioStringToFOURCCW(LPCWSTR sz, UINT uFlags) +{ + char szA[4]; + + WideCharToMultiByte( CP_ACP, 0, sz, 4, szA, sizeof(szA), NULL, NULL ); + return mmioStringToFOURCCA(szA,uFlags); +} + +/************************************************************************** + * mmioInstallIOProcA [WINMM.@] + */ +LPMMIOPROC WINAPI mmioInstallIOProcA(FOURCC fccIOProc, + LPMMIOPROC pIOProc, DWORD dwFlags) +{ + return MMIO_InstallIOProc(fccIOProc, pIOProc, dwFlags, MMIO_PROC_32A); +} + +/************************************************************************** + * mmioInstallIOProcW [WINMM.@] + */ +LPMMIOPROC WINAPI mmioInstallIOProcW(FOURCC fccIOProc, + LPMMIOPROC pIOProc, DWORD dwFlags) +{ + return MMIO_InstallIOProc(fccIOProc, pIOProc, dwFlags, MMIO_PROC_32W); +} + +/****************************************************************** + * MMIO_SendMessage + * + * + */ +LRESULT MMIO_SendMessage(HMMIO hmmio, UINT uMessage, LPARAM lParam1, + LPARAM lParam2, enum mmioProcType type) +{ + LPWINE_MMIO wm; + + TRACE("(%p, %u, %ld, %ld, %d)\n", hmmio, uMessage, lParam1, lParam2, type); + + if (uMessage < MMIOM_USER) + return MMSYSERR_INVALPARAM; + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + return send_message(wm->ioProc, &wm->info, uMessage, lParam1, lParam2, type); +} + +/************************************************************************** + * mmioSendMessage [WINMM.@] + */ +LRESULT WINAPI mmioSendMessage(HMMIO hmmio, UINT uMessage, + LPARAM lParam1, LPARAM lParam2) +{ + return MMIO_SendMessage(hmmio, uMessage, lParam1, lParam2, MMIO_PROC_32A); +} + +/************************************************************************** + * mmioDescend [WINMM.@] + */ +MMRESULT WINAPI mmioDescend(HMMIO hmmio, LPMMCKINFO lpck, + const MMCKINFO* lpckParent, UINT uFlags) +{ + DWORD dwOldPos; + FOURCC srchCkId; + FOURCC srchType; + + + TRACE("(%p, %p, %p, %04X);\n", hmmio, lpck, lpckParent, uFlags); + + if (lpck == NULL) + return MMSYSERR_INVALPARAM; + + dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR); + TRACE("dwOldPos=%ld\n", dwOldPos); + + if (lpckParent != NULL) { + TRACE("seek inside parent at %ld !\n", lpckParent->dwDataOffset); + /* EPP: was dwOldPos = mmioSeek(hmmio,lpckParent->dwDataOffset,SEEK_SET); */ + if (dwOldPos < lpckParent->dwDataOffset || + dwOldPos >= lpckParent->dwDataOffset + lpckParent->cksize) { + WARN("outside parent chunk\n"); + return MMIOERR_CHUNKNOTFOUND; + } + } + + /* The SDK docu says 'ckid' is used for all cases. Real World + * examples disagree -Marcus,990216. + */ + + srchType = 0; + /* find_chunk looks for 'ckid' */ + if (uFlags & MMIO_FINDCHUNK) + srchCkId = lpck->ckid; + /* find_riff and find_list look for 'fccType' */ + if (uFlags & MMIO_FINDLIST) { + srchCkId = FOURCC_LIST; + srchType = lpck->fccType; + } + if (uFlags & MMIO_FINDRIFF) { + srchCkId = FOURCC_RIFF; + srchType = lpck->fccType; + } + + if (uFlags & (MMIO_FINDCHUNK|MMIO_FINDLIST|MMIO_FINDRIFF)) { + TRACE("searching for %.4s.%.4s\n", + (LPSTR)&srchCkId, + srchType?(LPSTR)&srchType:"any "); + + while (TRUE) { + LONG ix; + + ix = mmioRead(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD)); + if (ix < 2*sizeof(DWORD)) { + mmioSeek(hmmio, dwOldPos, SEEK_SET); + WARN("return ChunkNotFound\n"); + return MMIOERR_CHUNKNOTFOUND; + } + lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD); + if (ix < lpck->dwDataOffset - dwOldPos) { + mmioSeek(hmmio, dwOldPos, SEEK_SET); + WARN("return ChunkNotFound\n"); + return MMIOERR_CHUNKNOTFOUND; + } + TRACE("ckid=%.4s fcc=%.4s cksize=%08lX !\n", + (LPSTR)&lpck->ckid, + srchType?(LPSTR)&lpck->fccType:"", + lpck->cksize); + if ((srchCkId == lpck->ckid) && + (!srchType || (srchType == lpck->fccType)) + ) + break; + + dwOldPos = lpck->dwDataOffset + ((lpck->cksize + 1) & ~1); + mmioSeek(hmmio, dwOldPos, SEEK_SET); + } + } else { + /* FIXME: unverified, does it do this? */ + /* NB: This part is used by WAVE_mciOpen, among others */ + if (mmioRead(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD)) < 3 * sizeof(DWORD)) { + mmioSeek(hmmio, dwOldPos, SEEK_SET); + WARN("return ChunkNotFound 2nd\n"); + return MMIOERR_CHUNKNOTFOUND; + } + lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD); + } + lpck->dwFlags = 0; + /* If we were looking for RIFF/LIST chunks, the final file position + * is after the chunkid. If we were just looking for the chunk + * it is after the cksize. So add 4 in RIFF/LIST case. + */ + if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) + mmioSeek(hmmio, lpck->dwDataOffset + sizeof(DWORD), SEEK_SET); + else + mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET); + TRACE("lpck: ckid=%.4s, cksize=%ld, dwDataOffset=%ld fccType=%08lX (%.4s)!\n", + (LPSTR)&lpck->ckid, lpck->cksize, lpck->dwDataOffset, + lpck->fccType, srchType?(LPSTR)&lpck->fccType:""); + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioAscend [WINMM.@] + */ +MMRESULT WINAPI mmioAscend(HMMIO hmmio, LPMMCKINFO lpck, UINT uFlags) +{ + TRACE("(%p, %p, %04X);\n", hmmio, lpck, uFlags); + + if (lpck->dwFlags & MMIO_DIRTY) { + DWORD dwOldPos, dwNewSize; + + TRACE("Chunk is dirty, checking if chunk's size is correct\n"); + dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR); + TRACE("dwOldPos=%ld lpck->dwDataOffset = %ld\n", dwOldPos, lpck->dwDataOffset); + dwNewSize = dwOldPos - lpck->dwDataOffset; + if (dwNewSize != lpck->cksize) { + TRACE("Nope: lpck->cksize=%ld dwNewSize=%ld\n", lpck->cksize, dwNewSize); + lpck->cksize = dwNewSize; + + /* pad odd size with 0 */ + if (dwNewSize & 1) { + char ch = 0; + mmioWrite(hmmio, &ch, 1); + } + mmioSeek(hmmio, lpck->dwDataOffset - sizeof(DWORD), SEEK_SET); + mmioWrite(hmmio, (LPSTR)&dwNewSize, sizeof(DWORD)); + } + lpck->dwFlags = 0; + } + + mmioSeek(hmmio, lpck->dwDataOffset + ((lpck->cksize + 1) & ~1), SEEK_SET); + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioCreateChunk [WINMM.@] + */ +MMRESULT WINAPI mmioCreateChunk(HMMIO hmmio, MMCKINFO* lpck, UINT uFlags) +{ + DWORD dwOldPos; + LONG size; + LONG ix; + + TRACE("(%p, %p, %04X);\n", hmmio, lpck, uFlags); + + dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR); + TRACE("dwOldPos=%ld\n", dwOldPos); + + if (uFlags == MMIO_CREATELIST) + lpck->ckid = FOURCC_LIST; + else if (uFlags == MMIO_CREATERIFF) + lpck->ckid = FOURCC_RIFF; + + TRACE("ckid=%.4s\n", (LPSTR)&lpck->ckid); + + size = 2 * sizeof(DWORD); + lpck->dwDataOffset = dwOldPos + size; + + if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) + size += sizeof(DWORD); + lpck->dwFlags = MMIO_DIRTY; + + ix = mmioWrite(hmmio, (LPSTR)lpck, size); + TRACE("after mmioWrite ix = %ld req = %ld, errno = %d\n",ix, size, errno); + if (ix < size) { + mmioSeek(hmmio, dwOldPos, SEEK_SET); + WARN("return CannotWrite\n"); + return MMIOERR_CANNOTWRITE; + } + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioRenameA [WINMM.@] + */ +MMRESULT WINAPI mmioRenameA(LPCSTR szFileName, LPCSTR szNewFileName, + const MMIOINFO* lpmmioinfo, DWORD dwFlags) +{ + struct IOProcList* ioProc = NULL; + struct IOProcList tmp; + FOURCC fcc; + + TRACE("('%s', '%s', %p, %08lX);\n", + debugstr_a(szFileName), debugstr_a(szNewFileName), lpmmioinfo, dwFlags); + + /* If both params are NULL, then parse the file name */ + if (lpmmioinfo && lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL) + { + fcc = MMIO_ParseExtA(szFileName); + if (fcc) ioProc = MMIO_FindProcNode(fcc); + } + + /* Handle any unhandled/error case from above. Assume DOS file */ + if (!lpmmioinfo || (lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL && ioProc == NULL)) + ioProc = MMIO_FindProcNode(FOURCC_DOS); + /* if just the four character code is present, look up IO proc */ + else if (lpmmioinfo->pIOProc == NULL) + ioProc = MMIO_FindProcNode(lpmmioinfo->fccIOProc); + else /* use relevant ioProc */ + { + ioProc = &tmp; + tmp.fourCC = lpmmioinfo->fccIOProc; + tmp.pIOProc = lpmmioinfo->pIOProc; + tmp.type = MMIO_PROC_32A; + tmp.count = 1; + } + + /* FIXME: should we actually pass lpmmioinfo down the drain ??? + * or make a copy of it because it's const ??? + */ + return send_message(ioProc, (LPMMIOINFO)lpmmioinfo, MMIOM_RENAME, + (LPARAM)szFileName, (LPARAM)szNewFileName, MMIO_PROC_32A); +} + +/************************************************************************** + * mmioRenameW [WINMM.@] + */ +MMRESULT WINAPI mmioRenameW(LPCWSTR szFileName, LPCWSTR szNewFileName, + const MMIOINFO* lpmmioinfo, DWORD dwFlags) +{ + LPSTR szFn = NULL; + LPSTR sznFn = NULL; + UINT ret; + INT len; + + if (szFileName) + { + len = WideCharToMultiByte( CP_ACP, 0, szFileName, -1, NULL, 0, NULL, NULL ); + szFn = HeapAlloc( GetProcessHeap(), 0, len ); + if (!szFn) return MMSYSERR_NOMEM; + WideCharToMultiByte( CP_ACP, 0, szFileName, -1, szFn, len, NULL, NULL ); + } + if (szNewFileName) + { + len = WideCharToMultiByte( CP_ACP, 0, szNewFileName, -1, NULL, 0, NULL, NULL ); + sznFn = HeapAlloc( GetProcessHeap(), 0, len ); + if (!sznFn) return MMSYSERR_NOMEM; + WideCharToMultiByte( CP_ACP, 0, szNewFileName, -1, sznFn, len, NULL, NULL ); + } + + ret = mmioRenameA(szFn, sznFn, lpmmioinfo, dwFlags); + + HeapFree(GetProcessHeap(),0,szFn); + HeapFree(GetProcessHeap(),0,sznFn); + return ret; +} diff --git a/reactos/lib/winmm/mmsystem.c b/reactos/lib/winmm/mmsystem.c new file mode 100644 index 00000000000..4ba03720ef0 --- /dev/null +++ b/reactos/lib/winmm/mmsystem.c @@ -0,0 +1,3174 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/* + * MMSYTEM functions + * + * Copyright 1993 Martin Ayotte + * 1998-2003 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 : + * 99/4 added mmTask and mmThread functions support + */ + +#include +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "winreg.h" +#include "ntstatus.h" +#include "winternl.h" +#include "wownt32.h" +#include "winnls.h" + +#include "wine/winuser16.h" +#include "winemm16.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mmsys); + +static WINE_MMTHREAD* WINMM_GetmmThread(HANDLE16); +static LPWINE_DRIVER DRIVER_OpenDriver16(LPCSTR, LPCSTR, LPARAM); +static LRESULT DRIVER_CloseDriver16(HDRVR16, LPARAM, LPARAM); +static LRESULT DRIVER_SendMessage16(HDRVR16, UINT, LPARAM, LPARAM); +static LRESULT MMIO_Callback16(SEGPTR, LPMMIOINFO, UINT, LPARAM, LPARAM); + +/* ################################################### + * # LIBRARY # + * ################################################### + */ + +/************************************************************************** + * DllEntryPoint (MMSYSTEM.2046) + * + * MMSYSTEM DLL entry point + * + */ +BOOL WINAPI MMSYSTEM_LibMain(DWORD fdwReason, HINSTANCE hinstDLL, WORD ds, + WORD wHeapSize, DWORD dwReserved1, WORD wReserved2) +{ + TRACE("%p 0x%lx\n", hinstDLL, fdwReason); + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + /* need to load WinMM in order to: + * - initiate correctly shared variables (WINMM_Init()) + */ + if (!GetModuleHandleA("WINMM.DLL") && !LoadLibraryA("WINMM.DLL")) + { + ERR("Could not load sibling WinMM.dll\n"); + return FALSE; + } + WINMM_IData->hWinMM16Instance = hinstDLL; + /* hook in our 16 bit function pointers */ + pFnGetMMThread16 = WINMM_GetmmThread; + pFnOpenDriver16 = DRIVER_OpenDriver16; + pFnCloseDriver16 = DRIVER_CloseDriver16; + pFnSendMessage16 = DRIVER_SendMessage16; + pFnMmioCallback16 = MMIO_Callback16; + pFnReleaseThunkLock = ReleaseThunkLock; + pFnRestoreThunkLock = RestoreThunkLock; + MMDRV_Init16(); + break; + case DLL_PROCESS_DETACH: + WINMM_IData->hWinMM16Instance = 0; + pFnGetMMThread16 = NULL; + pFnOpenDriver16 = NULL; + pFnCloseDriver16 = NULL; + pFnSendMessage16 = NULL; + pFnMmioCallback16 = NULL; + pFnReleaseThunkLock = NULL; + pFnRestoreThunkLock = NULL; + /* FIXME: add equivalent for MMDRV_Init16() */ + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + return TRUE; +} + +/************************************************************************** + * MMSYSTEM_WEP [MMSYSTEM.1] + */ +int WINAPI MMSYSTEM_WEP(HINSTANCE16 hInstance, WORD wDataSeg, + WORD cbHeapSize, LPSTR lpCmdLine) +{ + FIXME("STUB: Unloading MMSystem DLL ... hInst=%04X \n", hInstance); + return TRUE; +} + +/* ################################################### + * # PlaySound # + * ################################################### + */ + +/************************************************************************** + * PlaySound [MMSYSTEM.3] + */ +BOOL16 WINAPI PlaySound16(LPCSTR pszSound, HMODULE16 hmod, DWORD fdwSound) +{ + BOOL16 retv; + DWORD lc; + + if ((fdwSound & SND_RESOURCE) == SND_RESOURCE) + { + HGLOBAL16 handle; + HRSRC16 res; + + if (!(res = FindResource16( hmod, pszSound, "WAVE" ))) return FALSE; + if (!(handle = LoadResource16( hmod, res ))) return FALSE; + pszSound = LockResource16(handle); + fdwSound = (fdwSound & ~SND_RESOURCE) | SND_MEMORY; + /* FIXME: FreeResource16 */ + } + + ReleaseThunkLock(&lc); + retv = PlaySoundA(pszSound, 0, fdwSound); + RestoreThunkLock(lc); + + return retv; +} + +/************************************************************************** + * sndPlaySound [MMSYSTEM.2] + */ +BOOL16 WINAPI sndPlaySound16(LPCSTR lpszSoundName, UINT16 uFlags) +{ + BOOL16 retv; + DWORD lc; + + ReleaseThunkLock(&lc); + retv = sndPlaySoundA(lpszSoundName, uFlags); + RestoreThunkLock(lc); + + return retv; +} + +/* ################################################### + * # MISC # + * ################################################### + */ + +/************************************************************************** + * mmsystemGetVersion [MMSYSTEM.5] + * + */ +UINT16 WINAPI mmsystemGetVersion16(void) +{ + return mmsystemGetVersion(); +} + +/************************************************************************** + * DriverCallback [MMSYSTEM.31] + */ +BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HDRVR16 hDev, + WORD wMsg, DWORD dwUser, DWORD dwParam1, + DWORD dwParam2) +{ + return DriverCallback(dwCallBack, uFlags, HDRVR_32(hDev), wMsg, dwUser, dwParam1, dwParam2); +} + +/************************************************************************** + * OutputDebugStr [MMSYSTEM.30] + */ +void WINAPI OutputDebugStr16(LPCSTR str) +{ + OutputDebugStringA( str ); +} + + +/* ################################################### + * # MIXER # + * ################################################### + */ + +/************************************************************************** + * Mixer devices. New to Win95 + */ + +/************************************************************************** + * mixerGetNumDevs [MMSYSTEM.800] + */ +UINT16 WINAPI mixerGetNumDevs16(void) +{ + return MMDRV_GetNum(MMDRV_MIXER); +} + +/************************************************************************** + * mixerGetDevCaps [MMSYSTEM.801] + */ +UINT16 WINAPI mixerGetDevCaps16(UINT16 uDeviceID, LPMIXERCAPS16 lpCaps, + UINT16 uSize) +{ + MIXERCAPSA micA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = mixerGetDevCapsA(uDeviceID, &micA, sizeof(micA)); + if (ret == MMSYSERR_NOERROR) { + MIXERCAPS16 mic16; + mic16.wMid = micA.wMid; + mic16.wPid = micA.wPid; + mic16.vDriverVersion = micA.vDriverVersion; + strcpy(mic16.szPname, micA.szPname); + mic16.fdwSupport = micA.fdwSupport; + mic16.cDestinations = micA.cDestinations; + memcpy(lpCaps, &mic16, min(uSize, sizeof(mic16))); + } + return ret; +} + +/************************************************************************** + * mixerOpen [MMSYSTEM.802] + */ +UINT16 WINAPI mixerOpen16(LPHMIXER16 lphmix, UINT16 uDeviceID, DWORD dwCallback, + DWORD dwInstance, DWORD fdwOpen) +{ + HMIXER hmix; + UINT ret; + + ret = MIXER_Open(&hmix, uDeviceID, dwCallback, dwInstance, fdwOpen, FALSE); + if (lphmix) *lphmix = HMIXER_16(hmix); + return ret; +} + +/************************************************************************** + * mixerClose [MMSYSTEM.803] + */ +UINT16 WINAPI mixerClose16(HMIXER16 hMix) +{ + return mixerClose(HMIXER_32(hMix)); +} + +/************************************************************************** + * mixerGetID (MMSYSTEM.806) + */ +UINT16 WINAPI mixerGetID16(HMIXEROBJ16 hmix, LPUINT16 lpid, DWORD fdwID) +{ + UINT xid; + UINT ret = mixerGetID(HMIXEROBJ_32(hmix), &xid, fdwID); + + if (lpid) + *lpid = xid; + return ret; +} + +/************************************************************************** + * mixerGetControlDetails [MMSYSTEM.808] + */ +UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix, + LPMIXERCONTROLDETAILS16 lpmcd, + DWORD fdwDetails) +{ + DWORD ret = MMSYSERR_NOTENABLED; + SEGPTR sppaDetails; + + TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails); + + if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd)) + return MMSYSERR_INVALPARAM; + + sppaDetails = (SEGPTR)lpmcd->paDetails; + lpmcd->paDetails = MapSL(sppaDetails); + ret = mixerGetControlDetailsA(HMIXEROBJ_32(hmix), + (LPMIXERCONTROLDETAILS)lpmcd, fdwDetails); + lpmcd->paDetails = (LPVOID)sppaDetails; + + return ret; +} + +/************************************************************************** + * mixerGetLineControls [MMSYSTEM.807] + */ +UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16 hmix, + LPMIXERLINECONTROLS16 lpmlc16, + DWORD fdwControls) +{ + MIXERLINECONTROLSA mlcA; + DWORD ret; + unsigned int i; + LPMIXERCONTROL16 lpmc16; + + TRACE("(%04x, %p, %08lx)\n", hmix, lpmlc16, fdwControls); + + if (lpmlc16 == NULL || lpmlc16->cbStruct != sizeof(*lpmlc16) || + lpmlc16->cbmxctrl != sizeof(MIXERCONTROL16)) + return MMSYSERR_INVALPARAM; + + mlcA.cbStruct = sizeof(mlcA); + mlcA.dwLineID = lpmlc16->dwLineID; + mlcA.u.dwControlID = lpmlc16->u.dwControlID; + mlcA.u.dwControlType = lpmlc16->u.dwControlType; + mlcA.cControls = lpmlc16->cControls; + mlcA.cbmxctrl = sizeof(MIXERCONTROLA); + mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0, + mlcA.cControls * mlcA.cbmxctrl); + + ret = mixerGetLineControlsA(HMIXEROBJ_32(hmix), &mlcA, fdwControls); + + if (ret == MMSYSERR_NOERROR) { + lpmlc16->dwLineID = mlcA.dwLineID; + lpmlc16->u.dwControlID = mlcA.u.dwControlID; + lpmlc16->u.dwControlType = mlcA.u.dwControlType; + lpmlc16->cControls = mlcA.cControls; + + lpmc16 = MapSL(lpmlc16->pamxctrl); + + for (i = 0; i < mlcA.cControls; i++) { + lpmc16[i].cbStruct = sizeof(MIXERCONTROL16); + lpmc16[i].dwControlID = mlcA.pamxctrl[i].dwControlID; + lpmc16[i].dwControlType = mlcA.pamxctrl[i].dwControlType; + lpmc16[i].fdwControl = mlcA.pamxctrl[i].fdwControl; + lpmc16[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems; + strcpy(lpmc16[i].szShortName, mlcA.pamxctrl[i].szShortName); + strcpy(lpmc16[i].szName, mlcA.pamxctrl[i].szName); + /* sizeof(lpmc16[i].Bounds) == sizeof(mlcA.pamxctrl[i].Bounds) */ + memcpy(&lpmc16[i].Bounds, &mlcA.pamxctrl[i].Bounds, + sizeof(mlcA.pamxctrl[i].Bounds)); + /* sizeof(lpmc16[i].Metrics) == sizeof(mlcA.pamxctrl[i].Metrics) */ + memcpy(&lpmc16[i].Metrics, &mlcA.pamxctrl[i].Metrics, + sizeof(mlcA.pamxctrl[i].Metrics)); + } + } + + HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl); + + return ret; +} + +/************************************************************************** + * mixerGetLineInfo [MMSYSTEM.805] + */ +UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16 hmix, LPMIXERLINE16 lpmli16, + DWORD fdwInfo) +{ + MIXERLINEA mliA; + UINT ret; + + TRACE("(%04x, %p, %08lx)\n", hmix, lpmli16, fdwInfo); + + if (lpmli16 == NULL || lpmli16->cbStruct != sizeof(*lpmli16)) + return MMSYSERR_INVALPARAM; + + mliA.cbStruct = sizeof(mliA); + switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) { + case MIXER_GETLINEINFOF_COMPONENTTYPE: + mliA.dwComponentType = lpmli16->dwComponentType; + break; + case MIXER_GETLINEINFOF_DESTINATION: + mliA.dwDestination = lpmli16->dwDestination; + break; + case MIXER_GETLINEINFOF_LINEID: + mliA.dwLineID = lpmli16->dwLineID; + break; + case MIXER_GETLINEINFOF_SOURCE: + mliA.dwDestination = lpmli16->dwDestination; + mliA.dwSource = lpmli16->dwSource; + break; + case MIXER_GETLINEINFOF_TARGETTYPE: + mliA.Target.dwType = lpmli16->Target.dwType; + mliA.Target.wMid = lpmli16->Target.wMid; + mliA.Target.wPid = lpmli16->Target.wPid; + mliA.Target.vDriverVersion = lpmli16->Target.vDriverVersion; + strcpy(mliA.Target.szPname, lpmli16->Target.szPname); + break; + default: + FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo); + } + + ret = mixerGetLineInfoA(HMIXEROBJ_32(hmix), &mliA, fdwInfo); + + lpmli16->dwDestination = mliA.dwDestination; + lpmli16->dwSource = mliA.dwSource; + lpmli16->dwLineID = mliA.dwLineID; + lpmli16->fdwLine = mliA.fdwLine; + lpmli16->dwUser = mliA.dwUser; + lpmli16->dwComponentType = mliA.dwComponentType; + lpmli16->cChannels = mliA.cChannels; + lpmli16->cConnections = mliA.cConnections; + lpmli16->cControls = mliA.cControls; + strcpy(lpmli16->szShortName, mliA.szShortName); + strcpy(lpmli16->szName, mliA.szName); + lpmli16->Target.dwType = mliA.Target.dwType; + lpmli16->Target.dwDeviceID = mliA.Target.dwDeviceID; + lpmli16->Target.wMid = mliA.Target.wMid; + lpmli16->Target.wPid = mliA.Target.wPid; + lpmli16->Target.vDriverVersion = mliA.Target.vDriverVersion; + strcpy(lpmli16->Target.szPname, mliA.Target.szPname); + + return ret; +} + +/************************************************************************** + * mixerSetControlDetails [MMSYSTEM.809] + */ +UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16 hmix, + LPMIXERCONTROLDETAILS16 lpmcd, + DWORD fdwDetails) +{ + TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails); + return MMSYSERR_NOTENABLED; +} + +/************************************************************************** + * mixerMessage [MMSYSTEM.804] + */ +DWORD WINAPI mixerMessage16(HMIXER16 hmix, UINT16 uMsg, DWORD dwParam1, + DWORD dwParam2) +{ + return mixerMessage(HMIXER_32(hmix), uMsg, dwParam1, dwParam2); +} + +/************************************************************************** + * auxGetNumDevs [MMSYSTEM.350] + */ +UINT16 WINAPI auxGetNumDevs16(void) +{ + return MMDRV_GetNum(MMDRV_AUX); +} + +/* ################################################### + * # AUX # + * ################################################### + */ + +/************************************************************************** + * auxGetDevCaps [MMSYSTEM.351] + */ +UINT16 WINAPI auxGetDevCaps16(UINT16 uDeviceID, LPAUXCAPS16 lpCaps, UINT16 uSize) +{ + AUXCAPSA acA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA)); + if (ret == MMSYSERR_NOERROR) { + AUXCAPS16 ac16; + ac16.wMid = acA.wMid; + ac16.wPid = acA.wPid; + ac16.vDriverVersion = acA.vDriverVersion; + strcpy(ac16.szPname, acA.szPname); + ac16.wTechnology = acA.wTechnology; + ac16.dwSupport = acA.dwSupport; + memcpy(lpCaps, &ac16, min(uSize, sizeof(ac16))); + } + return ret; +} + +/************************************************************************** + * auxGetVolume [MMSYSTEM.352] + */ +UINT16 WINAPI auxGetVolume16(UINT16 uDeviceID, LPDWORD lpdwVolume) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume); + + if ((wmld = MMDRV_Get((HANDLE)(ULONG_PTR)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE); +} + +/************************************************************************** + * auxSetVolume [MMSYSTEM.353] + */ +UINT16 WINAPI auxSetVolume16(UINT16 uDeviceID, DWORD dwVolume) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume); + + if ((wmld = MMDRV_Get((HANDLE)(ULONG_PTR)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE); +} + +/************************************************************************** + * auxOutMessage [MMSYSTEM.354] + */ +DWORD WINAPI auxOutMessage16(UINT16 uDeviceID, UINT16 uMessage, DWORD dw1, DWORD dw2) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %04X, %08lX, %08lX)\n", uDeviceID, uMessage, dw1, dw2); + + switch (uMessage) { + case AUXDM_GETNUMDEVS: + case AUXDM_SETVOLUME: + /* no argument conversion needed */ + break; + case AUXDM_GETVOLUME: + return auxGetVolume16(uDeviceID, MapSL(dw1)); + case AUXDM_GETDEVCAPS: + return auxGetDevCaps16(uDeviceID, MapSL(dw1), dw2); + default: + TRACE("(%04x, %04x, %08lx, %08lx): unhandled message\n", + uDeviceID, uMessage, dw1, dw2); + break; + } + if ((wmld = MMDRV_Get((HANDLE)(ULONG_PTR)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE); +} + +/* ################################################### + * # MCI # + * ################################################### + */ + +/************************************************************************** + * mciGetErrorString [MMSYSTEM.706] + */ +BOOL16 WINAPI mciGetErrorString16(DWORD wError, LPSTR lpstrBuffer, UINT16 uLength) +{ + return mciGetErrorStringA(wError, lpstrBuffer, uLength); +} + +/************************************************************************** + * mciDriverNotify [MMSYSTEM.711] + */ +BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus) +{ + TRACE("(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus); + + return PostMessageA(HWND_32(hWndCallBack), MM_MCINOTIFY, wStatus, wDevID); +} + +/************************************************************************** + * mciGetDriverData [MMSYSTEM.708] + */ +DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID) +{ + return mciGetDriverData(uDeviceID); +} + +/************************************************************************** + * mciSetDriverData [MMSYSTEM.707] + */ +BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data) +{ + return mciSetDriverData(uDeviceID, data); +} + +/************************************************************************** + * mciSendCommand [MMSYSTEM.701] + */ +DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2) +{ + DWORD dwRet; + + TRACE("(%04X, %s, %08lX, %08lX)\n", + wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2); + + dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, FALSE); + dwRet = MCI_CleanUp(dwRet, wMsg, (DWORD)MapSL(dwParam2)); + TRACE("=> %ld\n", dwRet); + return dwRet; +} + +/************************************************************************** + * mciGetDeviceID [MMSYSTEM.703] + */ +UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName) +{ + TRACE("(\"%s\")\n", lpstrName); + + return MCI_GetDriverFromString(lpstrName); +} + +/************************************************************************** + * mciSetYieldProc [MMSYSTEM.714] + */ +BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC16 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 = (YIELDPROC)fpYieldProc; + wmd->dwYieldData = dwYieldData; + wmd->bIs32 = FALSE; + + return TRUE; +} + +/************************************************************************** + * mciGetDeviceIDFromElementID [MMSYSTEM.715] + */ +UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType) +{ + FIXME("(%lu, %s) stub\n", dwElementID, lpstrType); + return 0; +} + +/************************************************************************** + * mciGetYieldProc [MMSYSTEM.716] + */ +YIELDPROC16 WINAPI mciGetYieldProc16(UINT16 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 (YIELDPROC16)wmd->lpfnYieldProc; +} + +/************************************************************************** + * mciGetCreatorTask [MMSYSTEM.717] + */ +HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID) +{ + LPWINE_MCIDRIVER wmd; + HTASK16 ret = 0; + + if ((wmd = MCI_GetDriver(uDeviceID))) + ret = HTASK_16(wmd->CreatorThread); + + TRACE("(%u) => %04x\n", uDeviceID, ret); + return ret; +} + +/************************************************************************** + * mciDriverYield [MMSYSTEM.710] + */ +UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID) +{ + LPWINE_MCIDRIVER wmd; + UINT16 ret = 0; + + /* TRACE("(%04x)\n", uDeviceID); */ + + if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || wmd->bIs32) { + UserYield16(); + } else { + ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData); + } + + return ret; +} + +/* ################################################### + * # MIDI # + * ################################################### + */ + +/************************************************************************** + * midiOutGetNumDevs [MMSYSTEM.201] + */ +UINT16 WINAPI midiOutGetNumDevs16(void) +{ + return MMDRV_GetNum(MMDRV_MIDIOUT); +} + +/************************************************************************** + * midiOutGetDevCaps [MMSYSTEM.202] + */ +UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps, + UINT16 uSize) +{ + MIDIOUTCAPSA mocA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA)); + if (ret == MMSYSERR_NOERROR) { + MIDIOUTCAPS16 moc16; + moc16.wMid = mocA.wMid; + moc16.wPid = mocA.wPid; + moc16.vDriverVersion = mocA.vDriverVersion; + strcpy(moc16.szPname, mocA.szPname); + moc16.wTechnology = mocA.wTechnology; + moc16.wVoices = mocA.wVoices; + moc16.wNotes = mocA.wNotes; + moc16.wChannelMask = mocA.wChannelMask; + moc16.dwSupport = mocA.dwSupport; + memcpy(lpCaps, &moc16, min(uSize, sizeof(moc16))); + } + return ret; + } + +/************************************************************************** + * midiOutGetErrorText [MMSYSTEM.203] + */ +UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize) +{ + return midiOutGetErrorTextA(uError, lpText, uSize); +} + +/************************************************************************** + * midiOutOpen [MMSYSTEM.204] + */ +UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID, + DWORD dwCallback, DWORD dwInstance, DWORD dwFlags) +{ + HMIDIOUT hmo; + UINT ret; + + ret = MIDI_OutOpen(&hmo, uDeviceID, dwCallback, dwInstance, dwFlags, FALSE); + + if (lphMidiOut != NULL) *lphMidiOut = HMIDIOUT_16(hmo); + return ret; +} + +/************************************************************************** + * midiOutClose [MMSYSTEM.205] + */ +UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut) +{ + return midiOutClose(HMIDIOUT_32(hMidiOut)); +} + +/************************************************************************** + * midiOutPrepareHeader [MMSYSTEM.206] + */ +UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */ + SEGPTR lpsegMidiOutHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize); + + if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_PREPARE, lpsegMidiOutHdr, uSize, FALSE); +} + +/************************************************************************** + * midiOutUnprepareHeader [MMSYSTEM.207] + */ +UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */ + SEGPTR lpsegMidiOutHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + LPMIDIHDR16 lpMidiOutHdr = MapSL(lpsegMidiOutHdr); + + TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize); + + if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_UNPREPARE, lpsegMidiOutHdr, uSize, FALSE); +} + +/************************************************************************** + * midiOutShortMsg [MMSYSTEM.208] + */ +UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg) +{ + return midiOutShortMsg(HMIDIOUT_32(hMidiOut), dwMsg); +} + +/************************************************************************** + * midiOutLongMsg [MMSYSTEM.209] + */ +UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut, /* [in] */ + LPMIDIHDR16 lpsegMidiOutHdr, /* [???] NOTE: SEGPTR */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize); + + if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD_PTR)lpsegMidiOutHdr, uSize, FALSE); +} + +/************************************************************************** + * midiOutReset [MMSYSTEM.210] + */ +UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut) +{ + return midiOutReset(HMIDIOUT_32(hMidiOut)); +} + +/************************************************************************** + * midiOutGetVolume [MMSYSTEM.211] + */ +UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume) +{ + return midiOutGetVolume(HMIDIOUT_32(uDeviceID), lpdwVolume); +} + +/************************************************************************** + * midiOutSetVolume [MMSYSTEM.212] + */ +UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume) +{ + return midiOutSetVolume(HMIDIOUT_32(uDeviceID), dwVolume); +} + +/************************************************************************** + * midiOutCachePatches [MMSYSTEM.213] + */ +UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank, + WORD* lpwPatchArray, UINT16 uFlags) +{ + return midiOutCachePatches(HMIDIOUT_32(hMidiOut), uBank, lpwPatchArray, + uFlags); +} + +/************************************************************************** + * midiOutCacheDrumPatches [MMSYSTEM.214] + */ +UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch, + WORD* lpwKeyArray, UINT16 uFlags) +{ + return midiOutCacheDrumPatches(HMIDIOUT_32(hMidiOut), uPatch, lpwKeyArray, uFlags); +} + +/************************************************************************** + * midiOutGetID [MMSYSTEM.215] + */ +UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; + if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * midiOutMessage [MMSYSTEM.216] + */ +DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage, + DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + switch (uMessage) { + case MODM_OPEN: + case MODM_CLOSE: + FIXME("can't handle OPEN or CLOSE message!\n"); + return MMSYSERR_NOTSUPPORTED; + + case MODM_GETVOLUME: + return midiOutGetVolume16(hMidiOut, MapSL(dwParam1)); + case MODM_LONGDATA: + return midiOutLongMsg16(hMidiOut, MapSL(dwParam1), dwParam2); + case MODM_PREPARE: + /* lpMidiOutHdr is still a segmented pointer for this function */ + return midiOutPrepareHeader16(hMidiOut, dwParam1, dwParam2); + case MODM_UNPREPARE: + return midiOutUnprepareHeader16(hMidiOut, dwParam1, dwParam2); + } + return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); +} + +/************************************************************************** + * midiInGetNumDevs [MMSYSTEM.301] + */ +UINT16 WINAPI midiInGetNumDevs16(void) +{ + return MMDRV_GetNum(MMDRV_MIDIIN); +} + +/************************************************************************** + * midiInGetDevCaps [MMSYSTEM.302] + */ +UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID, LPMIDIINCAPS16 lpCaps, + UINT16 uSize) +{ + MIDIINCAPSA micA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = midiInGetDevCapsA(uDeviceID, &micA, uSize); + if (ret == MMSYSERR_NOERROR) { + MIDIINCAPS16 mic16; + mic16.wMid = micA.wMid; + mic16.wPid = micA.wPid; + mic16.vDriverVersion = micA.vDriverVersion; + strcpy(mic16.szPname, micA.szPname); + mic16.dwSupport = micA.dwSupport; + memcpy(lpCaps, &mic16, min(uSize, sizeof(mic16))); + } + return ret; +} + +/************************************************************************** + * midiInGetErrorText [MMSYSTEM.303] + */ +UINT16 WINAPI midiInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize) +{ + return midiInGetErrorTextA(uError, lpText, uSize); +} + +/************************************************************************** + * midiInOpen [MMSYSTEM.304] + */ +UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID, + DWORD dwCallback, DWORD dwInstance, DWORD dwFlags) +{ + HMIDIIN xhmid; + UINT ret; + + ret = MIDI_InOpen(&xhmid, uDeviceID, dwCallback, dwInstance, dwFlags, FALSE); + + if (lphMidiIn) *lphMidiIn = HMIDIIN_16(xhmid); + return ret; +} + +/************************************************************************** + * midiInClose [MMSYSTEM.305] + */ +UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn) +{ + return midiInClose(HMIDIIN_32(hMidiIn)); +} + +/************************************************************************** + * midiInPrepareHeader [MMSYSTEM.306] + */ +UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn, /* [in] */ + SEGPTR lpsegMidiInHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize); + + if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_PREPARE, lpsegMidiInHdr, uSize, FALSE); +} + +/************************************************************************** + * midiInUnprepareHeader [MMSYSTEM.307] + */ +UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn, /* [in] */ + SEGPTR lpsegMidiInHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + LPMIDIHDR16 lpMidiInHdr = MapSL(lpsegMidiInHdr); + + TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize); + + if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_UNPREPARE, lpsegMidiInHdr, uSize, FALSE); +} + +/************************************************************************** + * midiInAddBuffer [MMSYSTEM.308] + */ +UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn, /* [in] */ + MIDIHDR16* lpsegMidiInHdr, /* [???] NOTE: SEGPTR */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p, %d)\n", hMidiIn, lpsegMidiInHdr, uSize); + + if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD_PTR)lpsegMidiInHdr, uSize, FALSE); +} + +/************************************************************************** + * midiInStart [MMSYSTEM.309] + */ +UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn) +{ + return midiInStart(HMIDIIN_32(hMidiIn)); +} + +/************************************************************************** + * midiInStop [MMSYSTEM.310] + */ +UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn) +{ + return midiInStop(HMIDIIN_32(hMidiIn)); +} + +/************************************************************************** + * midiInReset [MMSYSTEM.311] + */ +UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn) +{ + return midiInReset(HMIDIIN_32(hMidiIn)); +} + +/************************************************************************** + * midiInGetID [MMSYSTEM.312] + */ +UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * midiInMessage [MMSYSTEM.313] + */ +DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage, + DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2); + + switch (uMessage) { + case MIDM_OPEN: + case MIDM_CLOSE: + FIXME("can't handle OPEN or CLOSE message!\n"); + return MMSYSERR_NOTSUPPORTED; + + case MIDM_GETDEVCAPS: + return midiInGetDevCaps16(hMidiIn, MapSL(dwParam1), dwParam2); + case MIDM_PREPARE: + return midiInPrepareHeader16(hMidiIn, dwParam1, dwParam2); + case MIDM_UNPREPARE: + return midiInUnprepareHeader16(hMidiIn, dwParam1, dwParam2); + case MIDM_ADDBUFFER: + return midiInAddBuffer16(hMidiIn, MapSL(dwParam1), dwParam2); + } + + if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE); +} + +/************************************************************************** + * midiStreamClose [MMSYSTEM.252] + */ +MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hMidiStrm) +{ + return midiStreamClose(HMIDISTRM_32(hMidiStrm)); +} + +/************************************************************************** + * midiStreamOpen [MMSYSTEM.251] + */ +MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phMidiStrm, LPUINT16 devid, + DWORD cMidi, DWORD dwCallback, + DWORD dwInstance, DWORD fdwOpen) +{ + HMIDISTRM hMidiStrm32; + MMRESULT ret; + UINT devid32; + + if (!phMidiStrm || !devid) + return MMSYSERR_INVALPARAM; + devid32 = *devid; + ret = MIDI_StreamOpen(&hMidiStrm32, &devid32, cMidi, dwCallback, + dwInstance, fdwOpen, FALSE); + *phMidiStrm = HMIDISTRM_16(hMidiStrm32); + *devid = devid32; + return ret; +} + +/************************************************************************** + * midiStreamOut [MMSYSTEM.254] + */ +MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hMidiStrm, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr) +{ + return midiStreamOut(HMIDISTRM_32(hMidiStrm), (LPMIDIHDR)lpMidiHdr, + cbMidiHdr); +} + +/************************************************************************** + * midiStreamPause [MMSYSTEM.255] + */ +MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hMidiStrm) +{ + return midiStreamPause(HMIDISTRM_32(hMidiStrm)); +} + +/************************************************************************** + * midiStreamPosition [MMSYSTEM.253] + */ +MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hMidiStrm, LPMMTIME16 lpmmt16, UINT16 cbmmt) +{ + MMTIME mmt32; + MMRESULT ret; + + if (!lpmmt16) + return MMSYSERR_INVALPARAM; + MMSYSTEM_MMTIME16to32(&mmt32, lpmmt16); + ret = midiStreamPosition(HMIDISTRM_32(hMidiStrm), &mmt32, sizeof(MMTIME)); + MMSYSTEM_MMTIME32to16(lpmmt16, &mmt32); + return ret; +} + +/************************************************************************** + * midiStreamProperty [MMSYSTEM.250] + */ +MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hMidiStrm, LPBYTE lpPropData, DWORD dwProperty) +{ + return midiStreamProperty(HMIDISTRM_32(hMidiStrm), lpPropData, dwProperty); +} + +/************************************************************************** + * midiStreamRestart [MMSYSTEM.256] + */ +MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hMidiStrm) +{ + return midiStreamRestart(HMIDISTRM_32(hMidiStrm)); +} + +/************************************************************************** + * midiStreamStop [MMSYSTEM.257] + */ +MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hMidiStrm) +{ + return midiStreamStop(HMIDISTRM_32(hMidiStrm)); +} + +/* ################################################### + * # WAVE # + * ################################################### + */ + +/************************************************************************** + * waveOutGetNumDevs [MMSYSTEM.401] + */ +UINT16 WINAPI waveOutGetNumDevs16(void) +{ + return MMDRV_GetNum(MMDRV_WAVEOUT); +} + +/************************************************************************** + * waveOutGetDevCaps [MMSYSTEM.402] + */ +UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID, + LPWAVEOUTCAPS16 lpCaps, UINT16 uSize) +{ + WAVEOUTCAPSA wocA; + UINT ret; + TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize); + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA)); + if (ret == MMSYSERR_NOERROR) { + WAVEOUTCAPS16 woc16; + woc16.wMid = wocA.wMid; + woc16.wPid = wocA.wPid; + woc16.vDriverVersion = wocA.vDriverVersion; + strcpy(woc16.szPname, wocA.szPname); + woc16.dwFormats = wocA.dwFormats; + woc16.wChannels = wocA.wChannels; + woc16.dwSupport = wocA.dwSupport; + memcpy(lpCaps, &woc16, min(uSize, sizeof(woc16))); + } + return ret; +} + +/************************************************************************** + * waveOutGetErrorText [MMSYSTEM.403] + */ +UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize) +{ + return waveOutGetErrorTextA(uError, lpText, uSize); +} + +/************************************************************************** + * waveOutOpen [MMSYSTEM.404] + */ +UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID, + const LPWAVEFORMATEX lpFormat, DWORD dwCallback, + DWORD dwInstance, DWORD dwFlags) +{ + HANDLE hWaveOut; + UINT ret; + + /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly + * call the 32 bit version + * however, we need to promote correctly the wave mapper id + * (0xFFFFFFFF and not 0x0000FFFF) + */ + ret = WAVE_Open(&hWaveOut, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID, + MMDRV_WAVEOUT, lpFormat, dwCallback, dwInstance, dwFlags, FALSE); + + if (lphWaveOut != NULL) *lphWaveOut = HWAVEOUT_16(hWaveOut); + return ret; +} + +/************************************************************************** + * waveOutClose [MMSYSTEM.405] + */ +UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveOutClose(HWAVEOUT_32(hWaveOut)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveOutPrepareHeader [MMSYSTEM.406] + */ +UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */ + SEGPTR lpsegWaveOutHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr); + + TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize); + + if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_PREPARE, lpsegWaveOutHdr, uSize, FALSE); +} + +/************************************************************************** + * waveOutUnprepareHeader [MMSYSTEM.407] + */ +UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */ + SEGPTR lpsegWaveOutHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr); + + TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize); + + if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_UNPREPARE, lpsegWaveOutHdr, uSize, FALSE); +} + +/************************************************************************** + * waveOutWrite [MMSYSTEM.408] + */ +UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut, /* [in] */ + LPWAVEHDR lpsegWaveOutHdr, /* [???] NOTE: SEGPTR */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize); + + if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_WRITE, (DWORD_PTR)lpsegWaveOutHdr, uSize, FALSE); +} + +/************************************************************************** + * waveOutBreakLoop [MMSYSTEM.419] + */ +UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut16) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveOutBreakLoop(HWAVEOUT_32(hWaveOut16)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveOutPause [MMSYSTEM.409] + */ +UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut16) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveOutPause(HWAVEOUT_32(hWaveOut16)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveOutReset [MMSYSTEM.411] + */ +UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut16) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveOutReset(HWAVEOUT_32(hWaveOut16)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveOutRestart [MMSYSTEM.410] + */ +UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut16) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveOutRestart(HWAVEOUT_32(hWaveOut16)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveOutGetPosition [MMSYSTEM.412] + */ +UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime, + UINT16 uSize) +{ + UINT ret; + MMTIME mmt; + + mmt.wType = lpTime->wType; + ret = waveOutGetPosition(HWAVEOUT_32(hWaveOut), &mmt, sizeof(mmt)); + MMSYSTEM_MMTIME32to16(lpTime, &mmt); + return ret; +} + +/************************************************************************** + * waveOutGetPitch [MMSYSTEM.413] + */ +UINT16 WINAPI waveOutGetPitch16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw) +{ + return waveOutGetPitch(HWAVEOUT_32(hWaveOut16), lpdw); +} + +/************************************************************************** + * waveOutSetPitch [MMSYSTEM.414] + */ +UINT16 WINAPI waveOutSetPitch16(HWAVEOUT16 hWaveOut16, DWORD dw) +{ + return waveOutSetPitch(HWAVEOUT_32(hWaveOut16), dw); +} + +/************************************************************************** + * waveOutGetPlaybackRate [MMSYSTEM.417] + */ +UINT16 WINAPI waveOutGetPlaybackRate16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw) +{ + return waveOutGetPlaybackRate(HWAVEOUT_32(hWaveOut16), lpdw); +} + +/************************************************************************** + * waveOutSetPlaybackRate [MMSYSTEM.418] + */ +UINT16 WINAPI waveOutSetPlaybackRate16(HWAVEOUT16 hWaveOut16, DWORD dw) +{ + return waveOutSetPlaybackRate(HWAVEOUT_32(hWaveOut16), dw); +} + +/************************************************************************** + * waveOutGetVolume [MMSYSTEM.415] + */ +UINT16 WINAPI waveOutGetVolume16(UINT16 devid, LPDWORD lpdw) +{ + return waveOutGetVolume(HWAVEOUT_32(devid), lpdw); +} + +/************************************************************************** + * waveOutSetVolume [MMSYSTEM.416] + */ +UINT16 WINAPI waveOutSetVolume16(UINT16 devid, DWORD dw) +{ + return waveOutSetVolume(HWAVEOUT_32(devid), dw); +} + +/************************************************************************** + * waveOutGetID [MMSYSTEM.420] + */ +UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; + + if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + return 0; +} + +/************************************************************************** + * waveOutMessage [MMSYSTEM.421] + */ +DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage, + DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) { + if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, TRUE)) != NULL) { + if (uMessage == DRV_QUERYDRVENTRY || uMessage == DRV_QUERYDEVNODE) + dwParam1 = (DWORD)MapSL(dwParam1); + 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, FALSE); +} + +/************************************************************************** + * waveInGetNumDevs [MMSYSTEM.501] + */ +UINT16 WINAPI waveInGetNumDevs16(void) +{ + return MMDRV_GetNum(MMDRV_WAVEIN); +} + +/************************************************************************** + * waveInGetDevCaps [MMSYSTEM.502] + */ +UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps, + UINT16 uSize) +{ + WAVEINCAPSA wicA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA)); + if (ret == MMSYSERR_NOERROR) { + WAVEINCAPS16 wic16; + wic16.wMid = wicA.wMid; + wic16.wPid = wicA.wPid; + wic16.vDriverVersion = wicA.vDriverVersion; + strcpy(wic16.szPname, wicA.szPname); + wic16.dwFormats = wicA.dwFormats; + wic16.wChannels = wicA.wChannels; + memcpy(lpCaps, &wic16, min(uSize, sizeof(wic16))); + } + return ret; +} + +/************************************************************************** + * waveInGetErrorText [MMSYSTEM.503] + */ +UINT16 WINAPI waveInGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize) +{ + return waveInGetErrorTextA(uError, lpText, uSize); +} + +/************************************************************************** + * waveInOpen [MMSYSTEM.504] + */ +UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID, + const LPWAVEFORMATEX lpFormat, DWORD dwCallback, + DWORD dwInstance, DWORD dwFlags) +{ + HANDLE hWaveIn; + UINT ret; + + /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly + * call the 32 bit version + * however, we need to promote correctly the wave mapper id + * (0xFFFFFFFF and not 0x0000FFFF) + */ + ret = WAVE_Open(&hWaveIn, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID, + MMDRV_WAVEIN, lpFormat, dwCallback, dwInstance, dwFlags, FALSE); + + if (lphWaveIn != NULL) *lphWaveIn = HWAVEIN_16(hWaveIn); + return ret; +} + +/************************************************************************** + * waveInClose [MMSYSTEM.505] + */ +UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveInClose(HWAVEIN_32(hWaveIn)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveInPrepareHeader [MMSYSTEM.506] + */ +UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn, /* [in] */ + SEGPTR lpsegWaveInHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr); + UINT16 ret; + + TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); + + if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE; + if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + lpWaveInHdr->dwBytesRecorded = 0; + + ret = MMDRV_Message(wmld, WIDM_PREPARE, lpsegWaveInHdr, uSize, FALSE); + return ret; +} + +/************************************************************************** + * waveInUnprepareHeader [MMSYSTEM.507] + */ +UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn, /* [in] */ + SEGPTR lpsegWaveInHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr); + + TRACE("(%04X, %08lx, %u);\n", hWaveIn, lpsegWaveInHdr, uSize); + + if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM; + + if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WIDM_UNPREPARE, lpsegWaveInHdr, uSize, FALSE); +} + +/************************************************************************** + * waveInAddBuffer [MMSYSTEM.508] + */ +UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn, /* [in] */ + WAVEHDR* lpsegWaveInHdr, /* [???] NOTE: SEGPTR */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p, %u);\n", hWaveIn, lpsegWaveInHdr, uSize); + + if (lpsegWaveInHdr == NULL) return MMSYSERR_INVALPARAM; + if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD_PTR)lpsegWaveInHdr, uSize, FALSE); +} + +/************************************************************************** + * waveInReset [MMSYSTEM.511] + */ +UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn16) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveInReset(HWAVEIN_32(hWaveIn16)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveInStart [MMSYSTEM.509] + */ +UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn16) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveInStart(HWAVEIN_32(hWaveIn16)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveInStop [MMSYSTEM.510] + */ +UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn16) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveInStop(HWAVEIN_32(hWaveIn16)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveInGetPosition [MMSYSTEM.512] + */ +UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime, + UINT16 uSize) +{ + UINT ret; + MMTIME mmt; + + mmt.wType = lpTime->wType; + ret = waveInGetPosition(HWAVEIN_32(hWaveIn), &mmt, sizeof(mmt)); + MMSYSTEM_MMTIME32to16(lpTime, &mmt); + return ret; +} + +/************************************************************************** + * waveInGetID [MMSYSTEM.513] + */ +UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; + + if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * waveInMessage [MMSYSTEM.514] + */ +DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage, + DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) { + if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, TRUE)) != NULL) { + if (uMessage == DRV_QUERYDRVENTRY || uMessage == DRV_QUERYDEVNODE) + dwParam1 = (DWORD)MapSL(dwParam1); + 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, FALSE); +} + +/* ################################################### + * # TASK # + * ################################################### + */ + +/*#define USE_MM_TSK_WINE*/ + +/************************************************************************** + * mmTaskCreate [MMSYSTEM.900] + * + * Creates a 16 bit MM task. It's entry point is lpFunc, and it should be + * called upon creation with dwPmt as parameter. + */ +HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt) +{ + HINSTANCE16 ret; + HINSTANCE16 handle; + char cmdline[16]; + DWORD showCmd = 0x40002; + LOADPARAMS16 lp; + + TRACE("(%08lx, %p, %08lx);\n", spProc, lphMmTask, dwPmt); + /* This to work requires NE modules to be started with a binary command line + * which is not currently the case. A patch exists but has never been committed. + * A workaround would be to integrate code for mmtask.tsk into Wine, but + * this requires tremendous work (starting with patching tools/build to + * create NE executables (and not only DLLs) for builtins modules. + * EP 99/04/25 + */ + FIXME("This is currently broken. It will fail\n"); + + cmdline[0] = 0x0d; + *(LPDWORD)(cmdline + 1) = (DWORD)spProc; + *(LPDWORD)(cmdline + 5) = dwPmt; + *(LPDWORD)(cmdline + 9) = 0; + + lp.hEnvironment = 0; + lp.cmdLine = MapLS(cmdline); + lp.showCmd = MapLS(&showCmd); + lp.reserved = 0; + +#ifndef USE_MM_TSK_WINE + handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", &lp); +#else + handle = LoadModule16("mmtask.tsk", &lp); +#endif + if (handle < 32) { + ret = (handle) ? 1 : 2; + handle = 0; + } else { + ret = 0; + } + if (lphMmTask) + *lphMmTask = handle; + + UnMapLS( lp.cmdLine ); + UnMapLS( lp.showCmd ); + TRACE("=> 0x%04x/%d\n", handle, ret); + return ret; +} + +#ifdef USE_MM_TSK_WINE +/* C equivalent to mmtask.tsk binary content */ +void mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si) +{ + int len = cmdLine[0x80]; + + if (len / 2 == 6) { + void (*fpProc)(DWORD) = MapSL(*((DWORD*)(cmdLine + 1))); + DWORD dwPmt = *((DWORD*)(cmdLine + 5)); + +#if 0 + InitTask16(); /* FIXME: pmts / from context ? */ + InitApp(di); +#endif + if (SetMessageQueue16(0x40)) { + WaitEvent16(0); + if (HIWORD(fpProc)) { + OldYield16(); +/* EPP StackEnter16(); */ + (fpProc)(dwPmt); + } + } + } + OldYield16(); + OldYield16(); + OldYield16(); + ExitProcess(0); +} +#endif + +/************************************************************************** + * mmTaskBlock [MMSYSTEM.902] + */ +void WINAPI mmTaskBlock16(HINSTANCE16 hInst) +{ + MSG msg; + + do { + GetMessageA(&msg, 0, 0, 0); + if (msg.hwnd) { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + } while (msg.message < 0x3A0); +} + +/************************************************************************** + * mmTaskSignal [MMSYSTEM.903] + */ +LRESULT WINAPI mmTaskSignal16(HTASK16 ht) +{ + TRACE("(%04x);\n", ht); + return PostThreadMessageW( HTASK_32(ht), WM_USER, 0, 0 ); +} + +/************************************************************************** + * mmGetCurrentTask [MMSYSTEM.904] + */ +HTASK16 WINAPI mmGetCurrentTask16(void) +{ + return GetCurrentTask(); +} + +/************************************************************************** + * mmTaskYield [MMSYSTEM.905] + */ +void WINAPI mmTaskYield16(void) +{ + MSG msg; + + if (PeekMessageA(&msg, 0, 0, 0, 0)) { + K32WOWYield16(); + } +} + +extern DWORD WINAPI GetProcessFlags(DWORD); + +/****************************************************************** + * WINMM_GetmmThread + * + * + */ +static WINE_MMTHREAD* WINMM_GetmmThread(HANDLE16 h) +{ + return (WINE_MMTHREAD*)MapSL( MAKESEGPTR(h, 0) ); +} + +DWORD WINAPI WINE_mmThreadEntryPoint(LPVOID); + +/************************************************************************** + * mmThreadCreate [MMSYSTEM.1120] + * + * undocumented + * Creates a MM thread, calling fpThreadAddr(dwPmt). + * dwFlags: + * bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc + * bit.1 set means to open a VxD for this thread (unsupported) + */ +LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE16 lpHndl, DWORD dwPmt, DWORD dwFlags) +{ + HANDLE16 hndl; + LRESULT ret; + + TRACE("(%p, %p, %08lx, %08lx)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags); + + hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT); + + if (hndl == 0) { + ret = 2; + } else { + WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); + +#if 0 + /* force mmtask routines even if mmthread is required */ + /* this will work only if the patch about binary cmd line and NE tasks + * is committed + */ + dwFlags |= 1; +#endif + + lpMMThd->dwSignature = WINE_MMTHREAD_CREATED; + lpMMThd->dwCounter = 0; + lpMMThd->hThread = 0; + lpMMThd->dwThreadID = 0; + lpMMThd->fpThread = (DWORD)fpThreadAddr; + lpMMThd->dwThreadPmt = dwPmt; + lpMMThd->dwSignalCount = 0; + lpMMThd->hEvent = 0; + lpMMThd->hVxD = 0; + lpMMThd->dwStatus = 0; + lpMMThd->dwFlags = dwFlags; + lpMMThd->hTask = 0; + + if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) { + lpMMThd->hEvent = CreateEventA(0, 0, 1, 0); + + TRACE("Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd); + if (lpMMThd->dwFlags & 2) { + /* as long as we don't support MM VxD in wine, we don't need + * to care about this flag + */ + /* FIXME("Don't know how to properly open VxD handles\n"); */ + /* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */ + } + + lpMMThd->hThread = CreateThread(0, 0, WINE_mmThreadEntryPoint, + (LPVOID)(DWORD_PTR)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID); + if (lpMMThd->hThread == 0) { + WARN("Couldn't create thread\n"); + /* clean-up(VxDhandle...); devicedirectio... */ + if (lpMMThd->hEvent != 0) + CloseHandle(lpMMThd->hEvent); + ret = 2; + } else { + TRACE("Got a nice thread hndl=%p id=0x%08lx\n", lpMMThd->hThread, lpMMThd->dwThreadID); + ret = 0; + } + } else { + /* get WINE_mmThreadEntryPoint() + * 2047 is its ordinal in mmsystem.spec + */ + FARPROC16 fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (LPCSTR)2047); + + TRACE("farproc seg=0x%08lx lin=%p\n", (DWORD)fp, MapSL((SEGPTR)fp)); + + ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl); + } + + if (ret == 0) { + if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread)) + WARN("Couldn't resume thread\n"); + + while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */ + UserYield16(); + } + } + } + + if (ret != 0) { + GlobalFree16(hndl); + hndl = 0; + } + + if (lpHndl) + *lpHndl = hndl; + + TRACE("ok => %ld\n", ret); + return ret; +} + +/************************************************************************** + * mmThreadSignal [MMSYSTEM.1121] + */ +void WINAPI mmThreadSignal16(HANDLE16 hndl) +{ + TRACE("(%04x)!\n", hndl); + + if (hndl) { + WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); + + lpMMThd->dwCounter++; + if (lpMMThd->hThread != 0) { + InterlockedIncrement(&lpMMThd->dwSignalCount); + SetEvent(lpMMThd->hEvent); + } else { + mmTaskSignal16(lpMMThd->hTask); + } + lpMMThd->dwCounter--; + } +} + +static void MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd) +{ + MSG msg; + DWORD ret; + + if (lpMMThd->dwThreadID != GetCurrentThreadId()) + ERR("Not called by thread itself\n"); + + for (;;) { + ResetEvent(lpMMThd->hEvent); + if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0) + break; + InterlockedIncrement(&lpMMThd->dwSignalCount); + + TRACE("S1\n"); + + ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT); + switch (ret) { + case WAIT_OBJECT_0: /* Event */ + TRACE("S2.1\n"); + break; + case WAIT_OBJECT_0 + 1: /* Msg */ + TRACE("S2.2\n"); + if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + break; + default: + WARN("S2.x unsupported ret val 0x%08lx\n", ret); + } + TRACE("S3\n"); + } +} + +/************************************************************************** + * mmThreadBlock [MMSYSTEM.1122] + */ +void WINAPI mmThreadBlock16(HANDLE16 hndl) +{ + TRACE("(%04x)!\n", hndl); + + if (hndl) { + WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); + + if (lpMMThd->hThread != 0) { + DWORD lc; + + ReleaseThunkLock(&lc); + MMSYSTEM_ThreadBlock(lpMMThd); + RestoreThunkLock(lc); + } else { + mmTaskBlock16(lpMMThd->hTask); + } + } + TRACE("done\n"); +} + +/************************************************************************** + * mmThreadIsCurrent [MMSYSTEM.1123] + */ +BOOL16 WINAPI mmThreadIsCurrent16(HANDLE16 hndl) +{ + BOOL16 ret = FALSE; + + TRACE("(%04x)!\n", hndl); + + if (hndl && mmThreadIsValid16(hndl)) { + WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); + ret = (GetCurrentThreadId() == lpMMThd->dwThreadID); + } + TRACE("=> %d\n", ret); + return ret; +} + +/************************************************************************** + * mmThreadIsValid [MMSYSTEM.1124] + */ +BOOL16 WINAPI mmThreadIsValid16(HANDLE16 hndl) +{ + BOOL16 ret = FALSE; + + TRACE("(%04x)!\n", hndl); + + if (hndl) { + WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); + + if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) && + lpMMThd->dwSignature == WINE_MMTHREAD_CREATED && + IsTask16(lpMMThd->hTask)) { + lpMMThd->dwCounter++; + if (lpMMThd->hThread != 0) { + DWORD dwThreadRet; + if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) && + dwThreadRet == STATUS_PENDING) { + ret = TRUE; + } + } else { + ret = TRUE; + } + lpMMThd->dwCounter--; + } + } + TRACE("=> %d\n", ret); + return ret; +} + +/************************************************************************** + * mmThreadGetTask [MMSYSTEM.1125] + */ +HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl) +{ + HANDLE16 ret = 0; + + TRACE("(%04x)\n", hndl); + + if (mmThreadIsValid16(hndl)) { + WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); + ret = lpMMThd->hTask; + } + return ret; +} + +/************************************************************************** + * __wine_mmThreadEntryPoint (MMSYSTEM.2047) + */ +DWORD WINAPI WINE_mmThreadEntryPoint(LPVOID p) +{ + HANDLE16 hndl = (HANDLE16)(DWORD_PTR)p; + WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); + + TRACE("(%04x %p)\n", hndl, lpMMThd); + + lpMMThd->hTask = LOWORD(GetCurrentTask()); + TRACE("[10-%p] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask); + lpMMThd->dwStatus = 0x10; + MMSYSTEM_ThreadBlock(lpMMThd); + TRACE("[20-%p]\n", lpMMThd->hThread); + lpMMThd->dwStatus = 0x20; + if (lpMMThd->fpThread) { + WOWCallback16(lpMMThd->fpThread, lpMMThd->dwThreadPmt); + } + lpMMThd->dwStatus = 0x30; + TRACE("[30-%p]\n", lpMMThd->hThread); + while (lpMMThd->dwCounter) { + Sleep(1); + /* K32WOWYield16();*/ + } + TRACE("[XX-%p]\n", lpMMThd->hThread); + /* paranoia */ + lpMMThd->dwSignature = WINE_MMTHREAD_DELETED; + /* close lpMMThread->hVxD directIO */ + if (lpMMThd->hEvent) + CloseHandle(lpMMThd->hEvent); + GlobalFree16(hndl); + TRACE("done\n"); + + return 0; +} + +typedef BOOL16 (WINAPI *MMCPLCALLBACK)(HWND, LPCSTR, LPCSTR, LPCSTR); + +/************************************************************************** + * mmShowMMCPLPropertySheet [MMSYSTEM.1150] + */ +BOOL16 WINAPI mmShowMMCPLPropertySheet16(HWND hWnd, LPCSTR lpStrDevice, + LPCSTR lpStrTab, LPCSTR lpStrTitle) +{ + HANDLE hndl; + BOOL16 ret = FALSE; + + TRACE("(%p \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle); + + hndl = LoadLibraryA("MMSYS.CPL"); + if (hndl != 0) { + MMCPLCALLBACK fp = (MMCPLCALLBACK)GetProcAddress(hndl, "ShowMMCPLPropertySheet"); + if (fp != NULL) { + DWORD lc; + ReleaseThunkLock(&lc); + ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle); + RestoreThunkLock(lc); + } + FreeLibrary(hndl); + } + + return ret; +} + +/************************************************************************** + * StackEnter [MMSYSTEM.32] + */ +void WINAPI StackEnter16(void) +{ +#ifdef __i386__ + /* mmsystem.dll from Win 95 does only this: so does Wine */ + __asm__("stc"); +#endif +} + +/************************************************************************** + * StackLeave [MMSYSTEM.33] + */ +void WINAPI StackLeave16(void) +{ +#ifdef __i386__ + /* mmsystem.dll from Win 95 does only this: so does Wine */ + __asm__("stc"); +#endif +} + +/************************************************************************** + * WMMMidiRunOnce [MMSYSTEM.8] + */ +void WINAPI WMMMidiRunOnce16(void) +{ + FIXME("(), stub!\n"); +} + +/* ################################################### + * # DRIVER # + * ################################################### + */ + +/************************************************************************** + * DRIVER_MapMsg32To16 [internal] + * + * Map a 32 bit driver message to a 16 bit driver message. + */ +static WINMM_MapType DRIVER_MapMsg32To16(WORD wMsg, DWORD* lParam1, DWORD* lParam2) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case DRV_LOAD: + case DRV_ENABLE: + case DRV_DISABLE: + case DRV_FREE: + case DRV_QUERYCONFIGURE: + case DRV_REMOVE: + case DRV_EXITSESSION: + case DRV_EXITAPPLICATION: + case DRV_POWER: + case DRV_CLOSE: /* should be 0/0 */ + case DRV_OPEN: /* pass through */ + /* lParam1 and lParam2 are not used */ + ret = WINMM_MAP_OK; + break; + case DRV_CONFIGURE: + case DRV_INSTALL: + /* lParam1 is a handle to a window (conf) or to a driver (inst) or not used, + * lParam2 is a pointer to DRVCONFIGINFO + */ + if (*lParam2) { + LPDRVCONFIGINFO16 dci16 = HeapAlloc( GetProcessHeap(), 0, sizeof(*dci16) ); + LPDRVCONFIGINFO dci32 = (LPDRVCONFIGINFO)(*lParam2); + + if (dci16) { + LPSTR str1; + INT len; + dci16->dwDCISize = sizeof(DRVCONFIGINFO16); + + if (dci32->lpszDCISectionName) { + len = WideCharToMultiByte( CP_ACP, 0, dci32->lpszDCISectionName, -1, NULL, 0, NULL, NULL ); + str1 = HeapAlloc( GetProcessHeap(), 0, len ); + if (str1) { + WideCharToMultiByte( CP_ACP, 0, dci32->lpszDCISectionName, -1, str1, len, NULL, NULL ); + dci16->lpszDCISectionName = MapLS( str1 ); + } else { + return WINMM_MAP_NOMEM; + } + } else { + dci16->lpszDCISectionName = 0L; + } + if (dci32->lpszDCIAliasName) { + len = WideCharToMultiByte( CP_ACP, 0, dci32->lpszDCIAliasName, -1, NULL, 0, NULL, NULL ); + str1 = HeapAlloc( GetProcessHeap(), 0, len ); + if (str1) { + WideCharToMultiByte( CP_ACP, 0, dci32->lpszDCIAliasName, -1, str1, len, NULL, NULL ); + dci16->lpszDCIAliasName = MapLS( str1 ); + } else { + return WINMM_MAP_NOMEM; + } + } else { + dci16->lpszDCISectionName = 0L; + } + } else { + return WINMM_MAP_NOMEM; + } + *lParam2 = MapLS( dci16 ); + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_OK; + } + break; + default: + if (!((wMsg >= 0x800 && wMsg < 0x900) || (wMsg >= 0x4000 && wMsg < 0x4100))) { + FIXME("Unknown message 0x%04x\n", wMsg); + } + ret = WINMM_MAP_OK; + } + return ret; +} + +/************************************************************************** + * DRIVER_UnMapMsg32To16 [internal] + * + * UnMap a 32 bit driver message to a 16 bit driver message. + */ +static WINMM_MapType DRIVER_UnMapMsg32To16(WORD wMsg, DWORD lParam1, DWORD lParam2) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case DRV_LOAD: + case DRV_ENABLE: + case DRV_DISABLE: + case DRV_FREE: + case DRV_QUERYCONFIGURE: + case DRV_REMOVE: + case DRV_EXITSESSION: + case DRV_EXITAPPLICATION: + case DRV_POWER: + case DRV_OPEN: + case DRV_CLOSE: + /* lParam1 and lParam2 are not used */ + break; + case DRV_CONFIGURE: + case DRV_INSTALL: + /* lParam1 is a handle to a window (or not used), lParam2 is a pointer to DRVCONFIGINFO, lParam2 */ + if (lParam2) { + LPDRVCONFIGINFO16 dci16 = MapSL(lParam2); + HeapFree( GetProcessHeap(), 0, MapSL(dci16->lpszDCISectionName) ); + HeapFree( GetProcessHeap(), 0, MapSL(dci16->lpszDCIAliasName) ); + UnMapLS( lParam2 ); + UnMapLS( dci16->lpszDCISectionName ); + UnMapLS( dci16->lpszDCIAliasName ); + HeapFree( GetProcessHeap(), 0, dci16 ); + } + ret = WINMM_MAP_OK; + break; + default: + if (!((wMsg >= 0x800 && wMsg < 0x900) || (wMsg >= 0x4000 && wMsg < 0x4100))) { + FIXME("Unknown message 0x%04x\n", wMsg); + } + ret = WINMM_MAP_OK; + } + return ret; +} + +/************************************************************************** + * DRIVER_TryOpenDriver16 [internal] + * + * Tries to load a 16 bit driver whose DLL's (module) name is lpFileName. + */ +static LPWINE_DRIVER DRIVER_OpenDriver16(LPCSTR fn, LPCSTR sn, LPARAM lParam2) +{ + LPWINE_DRIVER lpDrv = NULL; + LPCSTR cause = 0; + + TRACE("(%s, %08lX);\n", debugstr_a(sn), lParam2); + + lpDrv = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_DRIVER)); + if (lpDrv == NULL) {cause = "OOM"; goto exit;} + + /* FIXME: shall we do some black magic here on sn ? + * drivers32 => drivers + * mci32 => mci + * ... + */ + lpDrv->d.d16.hDriver16 = OpenDriver16(fn, sn, lParam2); + if (lpDrv->d.d16.hDriver16 == 0) {cause = "Not a 16 bit driver"; goto exit;} + lpDrv->dwFlags = WINE_GDF_16BIT; + + TRACE("=> %p\n", lpDrv); + return lpDrv; + exit: + HeapFree(GetProcessHeap(), 0, lpDrv); + TRACE("Unable to load 16 bit module %s: %s\n", debugstr_a(fn), cause); + return NULL; +} + +/****************************************************************** + * DRIVER_SendMessage16 + * + * + */ +static LRESULT DRIVER_SendMessage16(HDRVR16 hDrv16, UINT msg, + LPARAM lParam1, LPARAM lParam2) +{ + LRESULT ret = 0; + WINMM_MapType map; + + TRACE("Before sdm16 call hDrv=%04x wMsg=%04x p1=%08lx p2=%08lx\n", + hDrv16, msg, lParam1, lParam2); + + switch (map = DRIVER_MapMsg32To16(msg, &lParam1, &lParam2)) { + case WINMM_MAP_OKMEM: + case WINMM_MAP_OK: + ret = SendDriverMessage16(hDrv16, msg, lParam1, lParam2); + if (map == WINMM_MAP_OKMEM) + DRIVER_UnMapMsg32To16(msg, lParam1, lParam2); + default: + break; + } + return ret; +} + +/****************************************************************** + * DRIVER_CloseDriver16 + * + * + */ +static LRESULT DRIVER_CloseDriver16(HDRVR16 hDrv16, LPARAM lParam1, LPARAM lParam2) +{ + return CloseDriver16(hDrv16, lParam1, lParam2); +} + +/************************************************************************** + * DrvOpen [MMSYSTEM.1100] + */ +HDRVR16 WINAPI DrvOpen16(LPSTR lpDriverName, LPSTR lpSectionName, LPARAM lParam) +{ + return OpenDriver16(lpDriverName, lpSectionName, lParam); +} + +/************************************************************************** + * DrvClose [MMSYSTEM.1101] + */ +LRESULT WINAPI DrvClose16(HDRVR16 hDrv, LPARAM lParam1, LPARAM lParam2) +{ + return CloseDriver16(hDrv, lParam1, lParam2); +} + +/************************************************************************** + * DrvSendMessage [MMSYSTEM.1102] + */ +LRESULT WINAPI DrvSendMessage16(HDRVR16 hDrv, WORD msg, LPARAM lParam1, + LPARAM lParam2) +{ + return SendDriverMessage16(hDrv, msg, lParam1, lParam2); +} + +/************************************************************************** + * DrvGetModuleHandle [MMSYSTEM.1103] + */ +HANDLE16 WINAPI DrvGetModuleHandle16(HDRVR16 hDrv) +{ + return GetDriverModuleHandle16(hDrv); +} + +/************************************************************************** + * DrvDefDriverProc [MMSYSTEM.1104] + */ +LRESULT WINAPI DrvDefDriverProc16(DWORD dwDriverID, HDRVR16 hDrv, WORD wMsg, + DWORD dwParam1, DWORD dwParam2) +{ + return DefDriverProc16(dwDriverID, hDrv, wMsg, dwParam1, dwParam2); +} + +/************************************************************************** + * DriverProc [MMSYSTEM.6] + */ +LRESULT WINAPI DriverProc16(DWORD dwDevID, HDRVR16 hDrv, WORD wMsg, + DWORD dwParam1, DWORD dwParam2) +{ + TRACE("dwDevID=%08lx hDrv=%04x wMsg=%04x dwParam1=%08lx dwParam2=%08lx\n", + dwDevID, hDrv, wMsg, dwParam1, dwParam2); + + return DrvDefDriverProc16(dwDevID, hDrv, wMsg, dwParam1, dwParam2); +} + +/* ################################################### + * # TIME # + * ################################################### + */ + +/****************************************************************** + * MMSYSTEM_MMTIME32to16 + * + * + */ +void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32) +{ + mmt16->wType = mmt32->wType; + /* layout of rest is the same for 32/16, + * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding + */ + memcpy(&(mmt16->u), &(mmt32->u), sizeof(mmt16->u)); +} + +/****************************************************************** + * MMSYSTEM_MMTIME16to32 + * + * + */ +void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16) +{ + mmt32->wType = mmt16->wType; + /* layout of rest is the same for 32/16, + * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding + */ + memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u)); +} + +/************************************************************************** + * timeGetSystemTime [MMSYSTEM.601] + */ +MMRESULT16 WINAPI timeGetSystemTime16(LPMMTIME16 lpTime, UINT16 wSize) +{ + if (wSize >= sizeof(*lpTime)) { + lpTime->wType = TIME_MS; + lpTime->u.ms = GetTickCount(); + + TRACE("=> %lu\n", lpTime->u.ms); + } + + return 0; +} + +/************************************************************************** + * timeSetEvent [MMSYSTEM.602] + */ +MMRESULT16 WINAPI timeSetEvent16(UINT16 wDelay, UINT16 wResol, LPTIMECALLBACK16 lpFunc, + DWORD dwUser, UINT16 wFlags) +{ + if (wFlags & WINE_TIMER_IS32) + WARN("Unknown windows flag... wine internally used.. ooch\n"); + + return TIME_SetEventInternal(wDelay, wResol, (LPTIMECALLBACK)lpFunc, + dwUser, wFlags & ~WINE_TIMER_IS32); +} + +/************************************************************************** + * timeKillEvent [MMSYSTEM.603] + */ +MMRESULT16 WINAPI timeKillEvent16(UINT16 wID) +{ + return timeKillEvent(wID); +} + +/************************************************************************** + * timeGetDevCaps [MMSYSTEM.604] + */ +MMRESULT16 WINAPI timeGetDevCaps16(LPTIMECAPS16 lpCaps, UINT16 wSize) +{ + TIMECAPS caps; + MMRESULT ret; + TRACE("(%p, %u) !\n", lpCaps, wSize); + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = timeGetDevCaps(&caps, sizeof(caps)); + if (ret == MMSYSERR_NOERROR) { + TIMECAPS16 tc16; + tc16.wPeriodMin = caps.wPeriodMin; + tc16.wPeriodMax = caps.wPeriodMax; + memcpy(lpCaps, &tc16, min(wSize, sizeof(tc16))); + } + return ret; +} + +/************************************************************************** + * timeBeginPeriod [MMSYSTEM.605] + */ +MMRESULT16 WINAPI timeBeginPeriod16(UINT16 wPeriod) +{ + TRACE("(%u) !\n", wPeriod); + + return timeBeginPeriod(wPeriod); +} + +/************************************************************************** + * timeEndPeriod [MMSYSTEM.606] + */ +MMRESULT16 WINAPI timeEndPeriod16(UINT16 wPeriod) +{ + TRACE("(%u) !\n", wPeriod); + + return timeEndPeriod(wPeriod); +} + +/************************************************************************** + * mciSendString [MMSYSTEM.702] + */ +DWORD WINAPI mciSendString16(LPCSTR lpstrCommand, LPSTR lpstrRet, + UINT16 uRetLen, HWND16 hwndCallback) +{ + return mciSendStringA(lpstrCommand, lpstrRet, uRetLen, HWND_32(hwndCallback)); +} + +/************************************************************************** + * mciLoadCommandResource [MMSYSTEM.705] + */ +UINT16 WINAPI mciLoadCommandResource16(HINSTANCE16 hInst, LPCSTR resname, UINT16 type) +{ + HRSRC16 res; + HGLOBAL16 handle; + void *ptr; + + if (!(res = FindResource16( hInst, resname, (LPSTR)RT_RCDATA))) return MCI_NO_COMMAND_TABLE; + if (!(handle = LoadResource16( hInst, res ))) return MCI_NO_COMMAND_TABLE; + ptr = LockResource16(handle); + return MCI_SetCommandTable(ptr, type); + /* FIXME: FreeResource */ +} + +/************************************************************************** + * mciFreeCommandResource [MMSYSTEM.713] + */ +BOOL16 WINAPI mciFreeCommandResource16(UINT16 uTable) +{ + TRACE("(%04x)!\n", uTable); + + return mciFreeCommandResource(uTable); +} + +/* ################################################### + * # MMIO # + * ################################################### + */ + +/**************************************************************** + * MMIO_Map32To16 [INTERNAL] + */ +static LRESULT MMIO_Map32To16(DWORD wMsg, LPARAM* lp1, LPARAM* lp2) +{ + switch (wMsg) { + case MMIOM_CLOSE: + case MMIOM_SEEK: + /* nothing to do */ + break; + case MMIOM_OPEN: + case MMIOM_READ: + case MMIOM_WRITE: + case MMIOM_WRITEFLUSH: + *lp1 = MapLS( (void *)*lp1 ); + break; + case MMIOM_RENAME: + *lp1 = MapLS( (void *)*lp1 ); + *lp2 = MapLS( (void *)*lp2 ); + break; + default: + if (wMsg < MMIOM_USER) + TRACE("Not a mappable message (%ld)\n", wMsg); + } + return MMSYSERR_NOERROR; +} + +/**************************************************************** + * MMIO_UnMap32To16 [INTERNAL] + */ +static LRESULT MMIO_UnMap32To16(DWORD wMsg, LPARAM lParam1, LPARAM lParam2, + LPARAM lp1, LPARAM lp2) +{ + switch (wMsg) { + case MMIOM_CLOSE: + case MMIOM_SEEK: + /* nothing to do */ + break; + case MMIOM_OPEN: + case MMIOM_READ: + case MMIOM_WRITE: + case MMIOM_WRITEFLUSH: + UnMapLS( lp1 ); + break; + case MMIOM_RENAME: + UnMapLS( lp1 ); + UnMapLS( lp2 ); + break; + default: + if (wMsg < MMIOM_USER) + TRACE("Not a mappable message (%ld)\n", wMsg); + } + return MMSYSERR_NOERROR; +} + +/****************************************************************** + * MMIO_Callback16 + * + * + */ +static LRESULT MMIO_Callback16(SEGPTR cb16, LPMMIOINFO lpmmioinfo, UINT uMessage, + LPARAM lParam1, LPARAM lParam2) +{ + LRESULT result; + MMIOINFO16 mmioInfo16; + SEGPTR segmmioInfo16; + LPARAM lp1 = lParam1, lp2 = lParam2; + WORD args[7]; + + memset(&mmioInfo16, 0, sizeof(MMIOINFO16)); + mmioInfo16.lDiskOffset = lpmmioinfo->lDiskOffset; + mmioInfo16.adwInfo[0] = lpmmioinfo->adwInfo[0]; + mmioInfo16.adwInfo[1] = lpmmioinfo->adwInfo[1]; + mmioInfo16.adwInfo[2] = lpmmioinfo->adwInfo[2]; + mmioInfo16.adwInfo[3] = lpmmioinfo->adwInfo[3]; + /* map (lParam1, lParam2) into (lp1, lp2) 32=>16 */ + if ((result = MMIO_Map32To16(uMessage, &lp1, &lp2)) != MMSYSERR_NOERROR) + return result; + + segmmioInfo16 = MapLS(&mmioInfo16); + args[6] = HIWORD(segmmioInfo16); + args[5] = LOWORD(segmmioInfo16); + args[4] = uMessage; + args[3] = HIWORD(lp1); + args[2] = LOWORD(lp1); + args[1] = HIWORD(lp2); + args[0] = LOWORD(lp2); + WOWCallback16Ex( cb16, WCB16_PASCAL, sizeof(args), args, &result ); + UnMapLS(segmmioInfo16); + MMIO_UnMap32To16(uMessage, lParam1, lParam2, lp1, lp2); + + lpmmioinfo->lDiskOffset = mmioInfo16.lDiskOffset; + lpmmioinfo->adwInfo[0] = mmioInfo16.adwInfo[0]; + lpmmioinfo->adwInfo[1] = mmioInfo16.adwInfo[1]; + lpmmioinfo->adwInfo[2] = mmioInfo16.adwInfo[2]; + lpmmioinfo->adwInfo[3] = mmioInfo16.adwInfo[3]; + + return result; +} + +/****************************************************************** + * MMIO_ResetSegmentedData + * + */ +static LRESULT MMIO_SetSegmentedBuffer(HMMIO hmmio, SEGPTR ptr, BOOL release) +{ + LPWINE_MMIO wm; + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + if (release) UnMapLS(wm->segBuffer16); + wm->segBuffer16 = ptr; + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioOpen [MMSYSTEM.1210] + */ +HMMIO16 WINAPI mmioOpen16(LPSTR szFileName, MMIOINFO16* lpmmioinfo16, + DWORD dwOpenFlags) +{ + HMMIO ret; + + if (lpmmioinfo16) { + MMIOINFO mmioinfo; + + memset(&mmioinfo, 0, sizeof(mmioinfo)); + + mmioinfo.dwFlags = lpmmioinfo16->dwFlags; + mmioinfo.fccIOProc = lpmmioinfo16->fccIOProc; + mmioinfo.pIOProc = (LPMMIOPROC)lpmmioinfo16->pIOProc; + mmioinfo.cchBuffer = lpmmioinfo16->cchBuffer; + mmioinfo.pchBuffer = MapSL((DWORD)lpmmioinfo16->pchBuffer); + mmioinfo.adwInfo[0] = lpmmioinfo16->adwInfo[0]; + /* if we don't have a file name, it's likely a passed open file descriptor */ + if (!szFileName) + mmioinfo.adwInfo[0] = (DWORD)DosFileHandleToWin32Handle(mmioinfo.adwInfo[0]); + mmioinfo.adwInfo[1] = lpmmioinfo16->adwInfo[1]; + mmioinfo.adwInfo[2] = lpmmioinfo16->adwInfo[2]; + mmioinfo.adwInfo[3] = lpmmioinfo16->adwInfo[3]; + + ret = MMIO_Open(szFileName, &mmioinfo, dwOpenFlags, MMIO_PROC_16); + MMIO_SetSegmentedBuffer(mmioinfo.hmmio, (SEGPTR)lpmmioinfo16->pchBuffer, FALSE); + + lpmmioinfo16->wErrorRet = mmioinfo.wErrorRet; + lpmmioinfo16->hmmio = HMMIO_16(mmioinfo.hmmio); + } else { + ret = MMIO_Open(szFileName, NULL, dwOpenFlags, MMIO_PROC_32A); + } + return HMMIO_16(ret); +} + +/************************************************************************** + * mmioClose [MMSYSTEM.1211] + */ +MMRESULT16 WINAPI mmioClose16(HMMIO16 hmmio, UINT16 uFlags) +{ + MMIO_SetSegmentedBuffer(HMMIO_32(hmmio), (SEGPTR)NULL, TRUE); + return mmioClose(HMMIO_32(hmmio), uFlags); +} + +/************************************************************************** + * mmioRead [MMSYSTEM.1212] + */ +LONG WINAPI mmioRead16(HMMIO16 hmmio, HPSTR pch, LONG cch) +{ + return mmioRead(HMMIO_32(hmmio), pch, cch); +} + +/************************************************************************** + * mmioWrite [MMSYSTEM.1213] + */ +LONG WINAPI mmioWrite16(HMMIO16 hmmio, HPCSTR pch, LONG cch) +{ + return mmioWrite(HMMIO_32(hmmio),pch,cch); +} + +/************************************************************************** + * mmioSeek [MMSYSTEM.1214] + */ +LONG WINAPI mmioSeek16(HMMIO16 hmmio, LONG lOffset, INT16 iOrigin) +{ + return mmioSeek(HMMIO_32(hmmio), lOffset, iOrigin); +} + +/************************************************************************** + * mmioGetInfo [MMSYSTEM.1215] + */ +MMRESULT16 WINAPI mmioGetInfo16(HMMIO16 hmmio, MMIOINFO16* lpmmioinfo, UINT16 uFlags) +{ + MMIOINFO mmioinfo; + MMRESULT ret; + LPWINE_MMIO wm; + + TRACE("(0x%04x,%p,0x%08x)\n", hmmio, lpmmioinfo, uFlags); + + if ((wm = MMIO_Get(HMMIO_32(hmmio))) == NULL) + return MMSYSERR_INVALHANDLE; + + ret = mmioGetInfo(HMMIO_32(hmmio), &mmioinfo, uFlags); + if (ret != MMSYSERR_NOERROR) return ret; + + lpmmioinfo->dwFlags = mmioinfo.dwFlags; + lpmmioinfo->fccIOProc = mmioinfo.fccIOProc; + lpmmioinfo->pIOProc = (wm->ioProc->type == MMIO_PROC_16) ? + (LPMMIOPROC16)wm->ioProc->pIOProc : NULL; + lpmmioinfo->wErrorRet = mmioinfo.wErrorRet; + lpmmioinfo->hTask = HTASK_16(mmioinfo.hTask); + lpmmioinfo->cchBuffer = mmioinfo.cchBuffer; + lpmmioinfo->pchBuffer = (void*)wm->segBuffer16; + lpmmioinfo->pchNext = (void*)(wm->segBuffer16 + (mmioinfo.pchNext - mmioinfo.pchBuffer)); + lpmmioinfo->pchEndRead = (void*)(wm->segBuffer16 + (mmioinfo.pchEndRead - mmioinfo.pchBuffer)); + lpmmioinfo->pchEndWrite = (void*)(wm->segBuffer16 + (mmioinfo.pchEndWrite - mmioinfo.pchBuffer)); + lpmmioinfo->lBufOffset = mmioinfo.lBufOffset; + lpmmioinfo->lDiskOffset = mmioinfo.lDiskOffset; + lpmmioinfo->adwInfo[0] = mmioinfo.adwInfo[0]; + lpmmioinfo->adwInfo[1] = mmioinfo.adwInfo[1]; + lpmmioinfo->adwInfo[2] = mmioinfo.adwInfo[2]; + lpmmioinfo->adwInfo[3] = mmioinfo.adwInfo[3]; + lpmmioinfo->dwReserved1 = 0; + lpmmioinfo->dwReserved2 = 0; + lpmmioinfo->hmmio = HMMIO_16(mmioinfo.hmmio); + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioSetInfo [MMSYSTEM.1216] + */ +MMRESULT16 WINAPI mmioSetInfo16(HMMIO16 hmmio, const MMIOINFO16* lpmmioinfo, UINT16 uFlags) +{ + MMIOINFO mmioinfo; + MMRESULT ret; + + TRACE("(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags); + + ret = mmioGetInfo(HMMIO_32(hmmio), &mmioinfo, 0); + if (ret != MMSYSERR_NOERROR) return ret; + + /* check if seg and lin buffers are the same */ + if (mmioinfo.cchBuffer != lpmmioinfo->cchBuffer || + mmioinfo.pchBuffer != MapSL((DWORD)lpmmioinfo->pchBuffer)) + return MMSYSERR_INVALPARAM; + + /* check pointers coherence */ + if (lpmmioinfo->pchNext < lpmmioinfo->pchBuffer || + lpmmioinfo->pchNext > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer || + lpmmioinfo->pchEndRead < lpmmioinfo->pchBuffer || + lpmmioinfo->pchEndRead > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer || + lpmmioinfo->pchEndWrite < lpmmioinfo->pchBuffer || + lpmmioinfo->pchEndWrite > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer) + return MMSYSERR_INVALPARAM; + + mmioinfo.pchNext = mmioinfo.pchBuffer + (lpmmioinfo->pchNext - lpmmioinfo->pchBuffer); + mmioinfo.pchEndRead = mmioinfo.pchBuffer + (lpmmioinfo->pchEndRead - lpmmioinfo->pchBuffer); + mmioinfo.pchEndWrite = mmioinfo.pchBuffer + (lpmmioinfo->pchEndWrite - lpmmioinfo->pchBuffer); + + return mmioSetInfo(HMMIO_32(hmmio), &mmioinfo, uFlags); +} + +/************************************************************************** + * mmioSetBuffer [MMSYSTEM.1217] + */ +MMRESULT16 WINAPI mmioSetBuffer16(HMMIO16 hmmio, LPSTR pchBuffer, + LONG cchBuffer, UINT16 uFlags) +{ + MMRESULT ret = mmioSetBuffer(HMMIO_32(hmmio), MapSL((DWORD)pchBuffer), + cchBuffer, uFlags); + + if (ret == MMSYSERR_NOERROR) + MMIO_SetSegmentedBuffer(HMMIO_32(hmmio), (DWORD)pchBuffer, TRUE); + else + UnMapLS((DWORD)pchBuffer); + return ret; +} + +/************************************************************************** + * mmioFlush [MMSYSTEM.1218] + */ +MMRESULT16 WINAPI mmioFlush16(HMMIO16 hmmio, UINT16 uFlags) +{ + return mmioFlush(HMMIO_32(hmmio), uFlags); +} + +/*********************************************************************** + * mmioAdvance [MMSYSTEM.1219] + */ +MMRESULT16 WINAPI mmioAdvance16(HMMIO16 hmmio, MMIOINFO16* lpmmioinfo, UINT16 uFlags) +{ + MMIOINFO mmioinfo; + LRESULT ret; + + /* WARNING: this heavily relies on mmioAdvance implementation (for choosing which + * fields to init + */ + if (lpmmioinfo) + { + mmioinfo.pchBuffer = MapSL((DWORD)lpmmioinfo->pchBuffer); + mmioinfo.pchNext = MapSL((DWORD)lpmmioinfo->pchNext); + mmioinfo.dwFlags = lpmmioinfo->dwFlags; + mmioinfo.lBufOffset = lpmmioinfo->lBufOffset; + ret = mmioAdvance(HMMIO_32(hmmio), &mmioinfo, uFlags); + } + else + ret = mmioAdvance(HMMIO_32(hmmio), NULL, uFlags); + + if (ret != MMSYSERR_NOERROR) return ret; + + if (lpmmioinfo) + { + lpmmioinfo->dwFlags = mmioinfo.dwFlags; + lpmmioinfo->pchNext = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchNext - mmioinfo.pchBuffer)); + lpmmioinfo->pchEndRead = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchEndRead - mmioinfo.pchBuffer)); + lpmmioinfo->pchEndWrite = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchEndWrite - mmioinfo.pchBuffer)); + lpmmioinfo->lBufOffset = mmioinfo.lBufOffset; + lpmmioinfo->lDiskOffset = mmioinfo.lDiskOffset; + } + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioStringToFOURCC [MMSYSTEM.1220] + */ +FOURCC WINAPI mmioStringToFOURCC16(LPCSTR sz, UINT16 uFlags) +{ + return mmioStringToFOURCCA(sz, uFlags); +} + +/************************************************************************** + * mmioInstallIOProc [MMSYSTEM.1221] + */ +LPMMIOPROC16 WINAPI mmioInstallIOProc16(FOURCC fccIOProc, LPMMIOPROC16 pIOProc, + DWORD dwFlags) +{ + return (LPMMIOPROC16)MMIO_InstallIOProc(fccIOProc, (LPMMIOPROC)pIOProc, + dwFlags, MMIO_PROC_16); +} + +/************************************************************************** + * mmioSendMessage [MMSYSTEM.1222] + */ +LRESULT WINAPI mmioSendMessage16(HMMIO16 hmmio, UINT16 uMessage, + LPARAM lParam1, LPARAM lParam2) +{ + return MMIO_SendMessage(HMMIO_32(hmmio), uMessage, + lParam1, lParam2, MMIO_PROC_16); +} + +/************************************************************************** + * mmioDescend [MMSYSTEM.1223] + */ +MMRESULT16 WINAPI mmioDescend16(HMMIO16 hmmio, LPMMCKINFO lpck, + const MMCKINFO* lpckParent, UINT16 uFlags) +{ + return mmioDescend(HMMIO_32(hmmio), lpck, lpckParent, uFlags); +} + +/************************************************************************** + * mmioAscend [MMSYSTEM.1224] + */ +MMRESULT16 WINAPI mmioAscend16(HMMIO16 hmmio, MMCKINFO* lpck, UINT16 uFlags) +{ + return mmioAscend(HMMIO_32(hmmio),lpck,uFlags); +} + +/************************************************************************** + * mmioCreateChunk [MMSYSTEM.1225] + */ +MMRESULT16 WINAPI mmioCreateChunk16(HMMIO16 hmmio, MMCKINFO* lpck, UINT16 uFlags) +{ + return mmioCreateChunk(HMMIO_32(hmmio), lpck, uFlags); +} + +/************************************************************************** + * mmioRename [MMSYSTEM.1226] + */ +MMRESULT16 WINAPI mmioRename16(LPCSTR szFileName, LPCSTR szNewFileName, + MMIOINFO16* lpmmioinfo, DWORD dwRenameFlags) +{ + BOOL inst = FALSE; + MMRESULT ret; + MMIOINFO mmioinfo; + + if (lpmmioinfo != NULL && lpmmioinfo->pIOProc != NULL && + lpmmioinfo->fccIOProc == 0) { + FIXME("Can't handle this case yet\n"); + return MMSYSERR_ERROR; + } + + /* this is a bit hacky, but it'll work if we get a fourCC code or nothing. + * but a non installed ioproc without a fourcc won't do + */ + if (lpmmioinfo && lpmmioinfo->fccIOProc && lpmmioinfo->pIOProc) { + MMIO_InstallIOProc(lpmmioinfo->fccIOProc, (LPMMIOPROC)lpmmioinfo->pIOProc, + MMIO_INSTALLPROC, MMIO_PROC_16); + inst = TRUE; + } + memset(&mmioinfo, 0, sizeof(mmioinfo)); + mmioinfo.fccIOProc = lpmmioinfo->fccIOProc; + ret = mmioRenameA(szFileName, szNewFileName, &mmioinfo, dwRenameFlags); + if (inst) { + MMIO_InstallIOProc(lpmmioinfo->fccIOProc, NULL, + MMIO_REMOVEPROC, MMIO_PROC_16); + } + return ret; +} + +/* ################################################### + * # JOYSTICK # + * ################################################### + */ + +/************************************************************************** + * joyGetNumDevs [MMSYSTEM.101] + */ +UINT16 WINAPI joyGetNumDevs16(void) +{ + return joyGetNumDevs(); +} + +/************************************************************************** + * joyGetDevCaps [MMSYSTEM.102] + */ +MMRESULT16 WINAPI joyGetDevCaps16(UINT16 wID, LPJOYCAPS16 lpCaps, UINT16 wSize) +{ + JOYCAPSA jca; + MMRESULT ret = joyGetDevCapsA(wID, &jca, sizeof(jca)); + + if (ret != JOYERR_NOERROR) return ret; + lpCaps->wMid = jca.wMid; + lpCaps->wPid = jca.wPid; + strcpy(lpCaps->szPname, jca.szPname); + lpCaps->wXmin = jca.wXmin; + lpCaps->wXmax = jca.wXmax; + lpCaps->wYmin = jca.wYmin; + lpCaps->wYmax = jca.wYmax; + lpCaps->wZmin = jca.wZmin; + lpCaps->wZmax = jca.wZmax; + lpCaps->wNumButtons = jca.wNumButtons; + lpCaps->wPeriodMin = jca.wPeriodMin; + lpCaps->wPeriodMax = jca.wPeriodMax; + + if (wSize >= sizeof(JOYCAPS16)) { /* Win95 extensions ? */ + lpCaps->wRmin = jca.wRmin; + lpCaps->wRmax = jca.wRmax; + lpCaps->wUmin = jca.wUmin; + lpCaps->wUmax = jca.wUmax; + lpCaps->wVmin = jca.wVmin; + lpCaps->wVmax = jca.wVmax; + lpCaps->wCaps = jca.wCaps; + lpCaps->wMaxAxes = jca.wMaxAxes; + lpCaps->wNumAxes = jca.wNumAxes; + lpCaps->wMaxButtons = jca.wMaxButtons; + strcpy(lpCaps->szRegKey, jca.szRegKey); + strcpy(lpCaps->szOEMVxD, jca.szOEMVxD); + } + + return ret; +} + +/************************************************************************** + * joyGetPosEx [MMSYSTEM.110] + */ +MMRESULT16 WINAPI joyGetPosEx16(UINT16 wID, LPJOYINFOEX lpInfo) +{ + return joyGetPosEx(wID, lpInfo); +} + +/************************************************************************** + * joyGetPos [MMSYSTEM.103] + */ +MMRESULT16 WINAPI joyGetPos16(UINT16 wID, LPJOYINFO16 lpInfo) +{ + JOYINFO ji; + MMRESULT ret; + + TRACE("(%d, %p);\n", wID, lpInfo); + + if ((ret = joyGetPos(wID, &ji)) == JOYERR_NOERROR) { + lpInfo->wXpos = ji.wXpos; + lpInfo->wYpos = ji.wYpos; + lpInfo->wZpos = ji.wZpos; + lpInfo->wButtons = ji.wButtons; + } + return ret; +} + +/************************************************************************** + * joyGetThreshold [MMSYSTEM.104] + */ +MMRESULT16 WINAPI joyGetThreshold16(UINT16 wID, LPUINT16 lpThreshold) +{ + UINT t; + MMRESULT ret; + + ret = joyGetThreshold(wID, &t); + if (ret == JOYERR_NOERROR) + *lpThreshold = t; + return ret; +} + +/************************************************************************** + * joyReleaseCapture [MMSYSTEM.105] + */ +MMRESULT16 WINAPI joyReleaseCapture16(UINT16 wID) +{ + return joyReleaseCapture(wID); +} + +/************************************************************************** + * joySetCapture [MMSYSTEM.106] + */ +MMRESULT16 WINAPI joySetCapture16(HWND16 hWnd, UINT16 wID, UINT16 wPeriod, BOOL16 bChanged) +{ + return joySetCapture16(hWnd, wID, wPeriod, bChanged); +} + +/************************************************************************** + * joySetThreshold [MMSYSTEM.107] + */ +MMRESULT16 WINAPI joySetThreshold16(UINT16 wID, UINT16 wThreshold) +{ + return joySetThreshold16(wID,wThreshold); +} + +/************************************************************************** + * joySetCalibration [MMSYSTEM.109] + */ +MMRESULT16 WINAPI joySetCalibration16(UINT16 wID) +{ + FIXME("(%04X): stub.\n", wID); + return JOYERR_NOCANDO; +} diff --git a/reactos/lib/winmm/mmsystem.spec b/reactos/lib/winmm/mmsystem.spec new file mode 100644 index 00000000000..768e52ff66e --- /dev/null +++ b/reactos/lib/winmm/mmsystem.spec @@ -0,0 +1,176 @@ +#1 pascal MMSYSTEM_WEP(word word word ptr) MMSYSTEM_WEP +2 pascal sndPlaySound(ptr word) sndPlaySound16 +3 pascal PlaySound(ptr word long) PlaySound16 +5 pascal mmsystemGetVersion() mmsystemGetVersion16 +6 pascal DriverProc(long word word long long) DriverProc16 +8 pascal WMMMidiRunOnce() WMMMidiRunOnce16 +30 pascal -ret16 OutputDebugStr(str) OutputDebugStr16 +31 pascal DriverCallback(long word word word long long long) DriverCallback16 +32 pascal StackEnter() StackEnter16 +33 pascal StackLeave() StackLeave16 +34 stub MMDRVINSTALL +101 pascal joyGetNumDevs() joyGetNumDevs16 +102 pascal joyGetDevCaps(word ptr word) joyGetDevCaps16 +103 pascal joyGetPos(word ptr) joyGetPos16 +104 pascal joyGetThreshold(word ptr) joyGetThreshold16 +105 pascal joyReleaseCapture(word) joyReleaseCapture16 +106 pascal joySetCapture(word word word word) joySetCapture16 +107 pascal joySetThreshold(word word) joySetThreshold16 +109 pascal joySetCalibration(word) joySetCalibration16 +110 pascal joyGetPosEx(word ptr) joyGetPosEx16 +111 stub JOYCONFIGCHANGED +201 pascal midiOutGetNumDevs() midiOutGetNumDevs16 +202 pascal midiOutGetDevCaps(word ptr word) midiOutGetDevCaps16 +203 pascal midiOutGetErrorText(word ptr word) midiOutGetErrorText16 +204 pascal midiOutOpen(ptr word long long long) midiOutOpen16 +205 pascal midiOutClose(word) midiOutClose16 +206 pascal midiOutPrepareHeader(word segptr word) midiOutPrepareHeader16 +207 pascal midiOutUnprepareHeader(word segptr word) midiOutUnprepareHeader16 +208 pascal midiOutShortMsg(word long) midiOutShortMsg16 +209 pascal midiOutLongMsg(word segptr word) midiOutLongMsg16 +210 pascal midiOutReset(word) midiOutReset16 +211 pascal midiOutGetVolume(word ptr) midiOutGetVolume16 +212 pascal midiOutSetVolume(word long) midiOutSetVolume16 +213 pascal midiOutCachePatches(word word ptr word) midiOutCachePatches16 +214 pascal midiOutCacheDrumPatches(word word ptr word) midiOutCacheDrumPatches16 +215 pascal midiOutGetID(word ptr) midiOutGetID16 +216 pascal midiOutMessage(word word long long) midiOutMessage16 +250 pascal midiStreamProperty(word ptr long) midiStreamProperty16 +251 pascal midiStreamOpen(ptr ptr long long long long) midiStreamOpen16 +252 pascal midiStreamClose(word) midiStreamClose16 +253 pascal midiStreamPosition(word ptr word) midiStreamPosition16 +254 pascal midiStreamOut(word ptr word) midiStreamOut16 +255 pascal midiStreamPause(word) midiStreamPause16 +256 pascal midiStreamRestart(word) midiStreamRestart16 +257 pascal midiStreamStop(word) midiStreamStop16 +301 pascal midiInGetNumDevs() midiInGetNumDevs16 +302 pascal midiInGetDevCaps(word ptr word) midiInGetDevCaps16 +303 pascal midiInGetErrorText(word ptr word) midiInGetErrorText16 +304 pascal midiInOpen(ptr word long long long) midiInOpen16 +305 pascal midiInClose(word) midiInClose16 +306 pascal midiInPrepareHeader(word segptr word) midiInPrepareHeader16 +307 pascal midiInUnprepareHeader(word segptr word) midiInUnprepareHeader16 +308 pascal midiInAddBuffer(word segptr word) midiInAddBuffer16 +309 pascal midiInStart(word) midiInStart16 +310 pascal midiInStop(word) midiInStop16 +311 pascal midiInReset(word) midiInReset16 +312 pascal midiInGetID(word ptr) midiInGetID16 +313 pascal midiInMessage(word word long long) midiInMessage16 +350 pascal auxGetNumDevs() auxGetNumDevs16 +351 pascal auxGetDevCaps(word ptr word) auxGetDevCaps16 +352 pascal auxGetVolume(word ptr) auxGetVolume16 +353 pascal auxSetVolume(word long) auxSetVolume16 +354 pascal auxOutMessage(word word long long) auxOutMessage16 +401 pascal waveOutGetNumDevs() waveOutGetNumDevs16 +402 pascal waveOutGetDevCaps(word ptr word) waveOutGetDevCaps16 +403 pascal waveOutGetErrorText(word ptr word) waveOutGetErrorText16 +404 pascal waveOutOpen(ptr word ptr long long long) waveOutOpen16 +405 pascal waveOutClose(word) waveOutClose16 +406 pascal waveOutPrepareHeader(word segptr word) waveOutPrepareHeader16 +407 pascal waveOutUnprepareHeader(word segptr word) waveOutUnprepareHeader16 +408 pascal waveOutWrite(word segptr word) waveOutWrite16 +409 pascal waveOutPause(word) waveOutPause16 +410 pascal waveOutRestart(word) waveOutRestart16 +411 pascal waveOutReset(word) waveOutReset16 +412 pascal waveOutGetPosition(word ptr word) waveOutGetPosition16 +413 pascal waveOutGetPitch(word ptr) waveOutGetPitch16 +414 pascal waveOutSetPitch(word long) waveOutSetPitch16 +415 pascal waveOutGetVolume(word ptr) waveOutGetVolume16 +416 pascal waveOutSetVolume(word long) waveOutSetVolume16 +417 pascal waveOutGetPlaybackRate(word ptr) waveOutGetPlaybackRate16 +418 pascal waveOutSetPlaybackRate(word long) waveOutSetPlaybackRate16 +419 pascal waveOutBreakLoop(word) waveOutBreakLoop16 +420 pascal waveOutGetID(word ptr) waveOutGetID16 +421 pascal waveOutMessage(word word long long) waveOutMessage16 +501 pascal waveInGetNumDevs() waveInGetNumDevs16 +502 pascal waveInGetDevCaps(word ptr word) waveInGetDevCaps16 +503 pascal waveInGetErrorText(word ptr word) waveInGetErrorText16 +504 pascal waveInOpen(ptr word ptr long long long) waveInOpen16 +505 pascal waveInClose(word) waveInClose16 +506 pascal waveInPrepareHeader(word segptr word) waveInPrepareHeader16 +507 pascal waveInUnprepareHeader(word segptr word) waveInUnprepareHeader16 +508 pascal waveInAddBuffer(word segptr word) waveInAddBuffer16 +509 pascal waveInStart(word) waveInStart16 +510 pascal waveInStop(word) waveInStop16 +511 pascal waveInReset(word) waveInReset16 +512 pascal waveInGetPosition(word ptr word) waveInGetPosition16 +513 pascal waveInGetID(word ptr) waveInGetID16 +514 pascal waveInMessage(word word long long) waveInMessage16 +601 pascal timeGetSystemTime(ptr word) timeGetSystemTime16 +602 pascal timeSetEvent(word word segptr long word) timeSetEvent16 +603 pascal timeKillEvent(word) timeKillEvent16 +604 pascal timeGetDevCaps(ptr word) timeGetDevCaps16 +605 pascal timeBeginPeriod(word) timeBeginPeriod16 +606 pascal timeEndPeriod(word) timeEndPeriod16 +607 pascal timeGetTime() timeGetTime +701 pascal mciSendCommand(word word long long) mciSendCommand16 +702 pascal mciSendString(str ptr word word) mciSendString16 +703 pascal mciGetDeviceID(ptr) mciGetDeviceID16 +705 pascal mciLoadCommandResource(word str word) mciLoadCommandResource16 +706 pascal mciGetErrorString(long ptr word) mciGetErrorString16 +707 pascal mciSetDriverData(word long) mciSetDriverData16 +708 pascal mciGetDriverData(word) mciGetDriverData16 +710 pascal mciDriverYield(word) mciDriverYield16 +711 pascal mciDriverNotify(word word word) mciDriverNotify16 +712 pascal mciExecute(ptr) mciExecute +713 pascal mciFreeCommandResource(word) mciFreeCommandResource16 +714 pascal mciSetYieldProc(word ptr long) mciSetYieldProc16 +715 pascal mciGetDeviceIDFromElementID(long ptr) mciGetDeviceIDFromElementID16 +716 pascal mciGetYieldProc(word ptr) mciGetYieldProc16 +717 pascal mciGetCreatorTask(word) mciGetCreatorTask16 +800 pascal mixerGetNumDevs() mixerGetNumDevs16 +801 pascal mixerGetDevCaps(word ptr word) mixerGetDevCaps16 +802 pascal mixerOpen(ptr word long long long) mixerOpen16 +803 pascal mixerClose(word) mixerClose16 +804 pascal mixerMessage(word word long long) mixerMessage16 +805 pascal mixerGetLineInfo(word ptr long) mixerGetLineInfo16 +806 pascal mixerGetID(word ptr long) mixerGetID16 +807 pascal mixerGetLineControls(word ptr long) mixerGetLineControls16 +808 pascal mixerGetControlDetails(word ptr long) mixerGetControlDetails16 +809 pascal mixerSetControlDetails(word ptr long) mixerSetControlDetails16 +900 pascal mmTaskCreate(long ptr long) mmTaskCreate16 +902 pascal mmTaskBlock(word) mmTaskBlock16 +903 pascal mmTaskSignal(word) mmTaskSignal16 +904 pascal -ret16 mmGetCurrentTask() mmGetCurrentTask16 +905 pascal mmTaskYield() mmTaskYield16 +1100 pascal DrvOpen(str str long) DrvOpen16 +1101 pascal DrvClose(word long long) DrvClose16 +1102 pascal DrvSendMessage(word word long long) DrvSendMessage16 +1103 pascal DrvGetModuleHandle(word) DrvGetModuleHandle16 +1104 pascal DrvDefDriverProc(long word word long long) DrvDefDriverProc16 +1120 pascal mmThreadCreate(segptr ptr long long) mmThreadCreate16 +1121 pascal mmThreadSignal(word) mmThreadSignal16 +1122 pascal mmThreadBlock(word) mmThreadBlock16 +1123 pascal mmThreadIsCurrent(word) mmThreadIsCurrent16 +1124 pascal mmThreadIsValid(word) mmThreadIsValid16 +1125 pascal mmThreadGetTask(word) mmThreadGetTask16 +1150 pascal mmShowMMCPLPropertySheet(word str str str) mmShowMMCPLPropertySheet16 + +1210 pascal mmioOpen(str ptr long) mmioOpen16 +1211 pascal mmioClose(word word) mmioClose16 +1212 pascal mmioRead(word ptr long) mmioRead16 +1213 pascal mmioWrite(word ptr long) mmioWrite16 +1214 pascal mmioSeek(word long word) mmioSeek16 +1215 pascal mmioGetInfo(word ptr word) mmioGetInfo16 +1216 pascal mmioSetInfo(word ptr word) mmioSetInfo16 +1217 pascal mmioSetBuffer(word segptr long word) mmioSetBuffer16 +1218 pascal mmioFlush(word word) mmioFlush16 +1219 pascal mmioAdvance(word ptr word) mmioAdvance16 +1220 pascal mmioStringToFOURCC(str word) mmioStringToFOURCC16 +1221 pascal mmioInstallIOProc(long ptr long) mmioInstallIOProc16 +1222 pascal mmioSendMessage(word word long long) mmioSendMessage16 +1223 pascal mmioDescend(word ptr ptr word) mmioDescend16 +1224 pascal mmioAscend(word ptr word) mmioAscend16 +1225 pascal mmioCreateChunk(word ptr word) mmioCreateChunk16 +1226 pascal mmioRename(ptr ptr ptr long) mmioRename16 + +#2000 stub WINMMF_THUNKDATA16 +#2001 stub RING3_DEVLOADER +#2002 stub WINMMTILEBUFFER +#2003 stub WINMMUNTILEBUFFER +#2005 stub MCIGETTHUNKTABLE +#2006 stub WINMMSL_THUNKDATA16 + +2046 pascal DllEntryPoint(long word word word long word) MMSYSTEM_LibMain +# these are Wine only exported functions. Is there another way to do it ? +2047 pascal __wine_mmThreadEntryPoint(long) WINE_mmThreadEntryPoint diff --git a/reactos/lib/winmm/playsound.c b/reactos/lib/winmm/playsound.c new file mode 100644 index 00000000000..f7be898ca83 --- /dev/null +++ b/reactos/lib/winmm/playsound.c @@ -0,0 +1,525 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/* + * MMSYTEM 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 + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "wingdi.h" +#include "winuser.h" +#include "winreg.h" +#include "winemm.h" +#include "winternl.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winmm); + +static HMMIO get_mmioFromFile(LPCWSTR lpszName) +{ + HMMIO ret; + WCHAR buf[256]; + LPWSTR dummy; + + ret = mmioOpenW((LPWSTR)lpszName, NULL, + MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); + if (ret != 0) return ret; + if (SearchPathW(NULL, lpszName, NULL, sizeof(buf)/sizeof(buf[0]), buf, &dummy)) + { + return mmioOpenW(buf, NULL, + MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); + } + return 0; +} + +static HMMIO get_mmioFromProfile(UINT uFlags, LPCWSTR lpszName) +{ + WCHAR str[128]; + LPWSTR ptr; + HMMIO hmmio; + HKEY hRegSnd, hRegApp, hScheme, hSnd; + DWORD err, type, count; + + static const WCHAR wszSounds[] = {'S','o','u','n','d','s',0}; + static const WCHAR wszDefault[] = {'D','e','f','a','u','l','t',0}; + static const WCHAR wszKey[] = {'A','p','p','E','v','e','n','t','s','\\', + 'S','c','h','e','m','e','s','\\', + 'A','p','p','s',0}; + static const WCHAR wszDotDefault[] = {'.','D','e','f','a','u','l','t',0}; + static const WCHAR wszDotCurrent[] = {'.','C','u','r','r','e','n','t',0}; + static const WCHAR wszNull[] = {0}; + + TRACE("searching in SystemSound list for %s\n", debugstr_w(lpszName)); + GetProfileStringW(wszSounds, lpszName, wszNull, str, sizeof(str)/sizeof(str[0])); + if (lstrlenW(str) == 0) + { + if (uFlags & SND_NODEFAULT) goto next; + GetProfileStringW(wszSounds, wszDefault, wszNull, str, sizeof(str)/sizeof(str[0])); + if (lstrlenW(str) == 0) goto next; + } + for (ptr = str; *ptr && *ptr != ','; ptr++); + if (*ptr) *ptr = 0; + hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); + if (hmmio != 0) return hmmio; + next: + /* we look up the registry under + * HKCU\AppEvents\Schemes\Apps\.Default + * HKCU\AppEvents\Schemes\Apps\ + */ + if (RegOpenKeyW(HKEY_CURRENT_USER, wszKey, &hRegSnd) != 0) goto none; + if (uFlags & SND_APPLICATION) + { + DWORD len; + + err = 1; /* error */ + len = GetModuleFileNameW(0, str, sizeof(str)/sizeof(str[0])); + if (len > 0 && len < sizeof(str)/sizeof(str[0])) + { + for (ptr = str + lstrlenW(str) - 1; ptr >= str; ptr--) + { + if (*ptr == '.') *ptr = 0; + if (*ptr == '\\') + { + err = RegOpenKeyW(hRegSnd, ptr+1, &hRegApp); + break; + } + } + } + } + else + { + err = RegOpenKeyW(hRegSnd, wszDotDefault, &hRegApp); + } + RegCloseKey(hRegSnd); + if (err != 0) goto none; + err = RegOpenKeyW(hRegApp, lpszName, &hScheme); + RegCloseKey(hRegApp); + if (err != 0) goto none; + /* what's the difference between .Current and .Default ? */ + err = RegOpenKeyW(hScheme, wszDotDefault, &hSnd); + if (err != 0) + { + err = RegOpenKeyW(hScheme, wszDotCurrent, &hSnd); + RegCloseKey(hScheme); + if (err != 0) + goto none; + } + count = sizeof(str)/sizeof(str[0]); + err = RegQueryValueExW(hSnd, NULL, 0, &type, (LPBYTE)str, &count); + RegCloseKey(hSnd); + if (err != 0 || !*str) goto none; + hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); + if (hmmio) return hmmio; + none: + WARN("can't find SystemSound='%s' !\n", debugstr_w(lpszName)); + return 0; +} + +struct playsound_data +{ + HANDLE hEvent; + DWORD dwEventCount; +}; + +static void CALLBACK PlaySound_Callback(HWAVEOUT hwo, UINT uMsg, + DWORD dwInstance, + DWORD dwParam1, DWORD dwParam2) +{ + struct playsound_data* s = (struct playsound_data*)dwInstance; + + switch (uMsg) { + case WOM_OPEN: + case WOM_CLOSE: + break; + case WOM_DONE: + InterlockedIncrement(&s->dwEventCount); + TRACE("Returning waveHdr=%lx\n", dwParam1); + SetEvent(s->hEvent); + break; + default: + ERR("Unknown uMsg=%d\n", uMsg); + } +} + +static void PlaySound_WaitDone(struct playsound_data* s) +{ + for (;;) { + ResetEvent(s->hEvent); + if (InterlockedDecrement(&s->dwEventCount) >= 0) break; + InterlockedIncrement(&s->dwEventCount); + + WaitForSingleObject(s->hEvent, INFINITE); + } +} + +static BOOL PlaySound_IsString(DWORD fdwSound, const void* psz) +{ + /* SND_RESOURCE is 0x40004 while + * SND_MEMORY is 0x00004 + */ + switch (fdwSound & (SND_RESOURCE|SND_ALIAS|SND_FILENAME)) + { + case SND_RESOURCE: return HIWORD(psz) != 0; /* by name or by ID ? */ + case SND_MEMORY: return FALSE; + case SND_ALIAS: /* what about ALIAS_ID ??? */ + case SND_FILENAME: + case 0: return TRUE; + default: FIXME("WTF\n"); return FALSE; + } +} + +static void PlaySound_Free(WINE_PLAYSOUND* wps) +{ + WINE_PLAYSOUND** p; + + EnterCriticalSection(&WINMM_IData->cs); + for (p = &WINMM_IData->lpPlaySound; *p && *p != wps; p = &((*p)->lpNext)); + if (*p) *p = (*p)->lpNext; + if (WINMM_IData->lpPlaySound == NULL) SetEvent(WINMM_IData->psLastEvent); + LeaveCriticalSection(&WINMM_IData->cs); + if (wps->bAlloc) HeapFree(GetProcessHeap(), 0, (void*)wps->pszSound); + if (wps->hThread) CloseHandle(wps->hThread); + HeapFree(GetProcessHeap(), 0, wps); +} + +static WINE_PLAYSOUND* PlaySound_Alloc(const void* pszSound, HMODULE hmod, + DWORD fdwSound, BOOL bUnicode) +{ + WINE_PLAYSOUND* wps; + + wps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wps)); + if (!wps) return NULL; + + wps->hMod = hmod; + wps->fdwSound = fdwSound; + if (PlaySound_IsString(fdwSound, pszSound)) + { + if (bUnicode) + { + if (fdwSound & SND_ASYNC) + { + wps->pszSound = HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(pszSound)+1) * sizeof(WCHAR)); + if (!wps->pszSound) goto oom_error; + lstrcpyW((LPWSTR)wps->pszSound, pszSound); + wps->bAlloc = TRUE; + } + else + wps->pszSound = pszSound; + } + else + { + UNICODE_STRING usBuffer; + RtlCreateUnicodeStringFromAsciiz(&usBuffer, pszSound); + wps->pszSound = usBuffer.Buffer; + if (!wps->pszSound) goto oom_error; + wps->bAlloc = TRUE; + } + } + else + wps->pszSound = pszSound; + + return wps; + oom_error: + PlaySound_Free(wps); + return NULL; +} + +static DWORD WINAPI proc_PlaySound(LPVOID arg) +{ + WINE_PLAYSOUND* wps = (WINE_PLAYSOUND*)arg; + BOOL bRet = FALSE; + HMMIO hmmio = 0; + MMCKINFO ckMainRIFF; + MMCKINFO mmckInfo; + LPWAVEFORMATEX lpWaveFormat = NULL; + HWAVEOUT hWave = 0; + LPWAVEHDR waveHdr = NULL; + INT count, bufsize, left, index; + struct playsound_data s; + void* data; + + s.hEvent = 0; + + TRACE("SoundName='%s' !\n", debugstr_w(wps->pszSound)); + + /* if resource, grab it */ + if ((wps->fdwSound & SND_RESOURCE) == SND_RESOURCE) { + static const WCHAR wszWave[] = {'W','A','V','E',0}; + HRSRC hRes; + HGLOBAL hGlob; + + if ((hRes = FindResourceW(wps->hMod, wps->pszSound, wszWave)) == 0 || + (hGlob = LoadResource(wps->hMod, hRes)) == 0) + goto errCleanUp; + if ((data = LockResource(hGlob)) == NULL) { + FreeResource(hGlob); + goto errCleanUp; + } + FreeResource(hGlob); + } else + data = (void*)wps->pszSound; + + /* construct an MMIO stream (either in memory, or from a file */ + if (wps->fdwSound & SND_MEMORY) + { /* NOTE: SND_RESOURCE has the SND_MEMORY bit set */ + MMIOINFO mminfo; + + memset(&mminfo, 0, sizeof(mminfo)); + mminfo.fccIOProc = FOURCC_MEM; + mminfo.pchBuffer = (LPSTR)data; + mminfo.cchBuffer = -1; /* FIXME: when a resource, could grab real size */ + TRACE("Memory sound %p\n", data); + hmmio = mmioOpenW(NULL, &mminfo, MMIO_READ); + } + else if (wps->fdwSound & SND_ALIAS) + { + hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound); + } + else if (wps->fdwSound & SND_FILENAME) + { + hmmio = get_mmioFromFile(wps->pszSound); + } + else + { + if ((hmmio = get_mmioFromProfile(wps->fdwSound | SND_NODEFAULT, wps->pszSound)) == 0) + { + if ((hmmio = get_mmioFromFile(wps->pszSound)) == 0) + { + hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound); + } + } + } + if (hmmio == 0) goto errCleanUp; + + if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0)) + goto errCleanUp; + + TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n", + (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize); + + if ((ckMainRIFF.ckid != FOURCC_RIFF) || + (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) + goto errCleanUp; + + mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' '); + if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK)) + goto errCleanUp; + + TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n", + (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize); + + lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize); + if (mmioRead(hmmio, (HPSTR)lpWaveFormat, mmckInfo.cksize) < sizeof(WAVEFORMAT)) + goto errCleanUp; + + TRACE("wFormatTag=%04X !\n", lpWaveFormat->wFormatTag); + TRACE("nChannels=%d \n", lpWaveFormat->nChannels); + TRACE("nSamplesPerSec=%ld\n", lpWaveFormat->nSamplesPerSec); + TRACE("nAvgBytesPerSec=%ld\n", lpWaveFormat->nAvgBytesPerSec); + TRACE("nBlockAlign=%d \n", lpWaveFormat->nBlockAlign); + TRACE("wBitsPerSample=%u !\n", lpWaveFormat->wBitsPerSample); + + /* move to end of 'fmt ' chunk */ + mmioAscend(hmmio, &mmckInfo, 0); + + mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a'); + if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK)) + goto errCleanUp; + + TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n", + (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize); + + s.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + + if (waveOutOpen(&hWave, WAVE_MAPPER, lpWaveFormat, (DWORD)PlaySound_Callback, + (DWORD)&s, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) + goto errCleanUp; + + /* make it so that 3 buffers per second are needed */ + bufsize = (((lpWaveFormat->nAvgBytesPerSec / 3) - 1) / lpWaveFormat->nBlockAlign + 1) * + lpWaveFormat->nBlockAlign; + waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize); + waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR); + waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize; + waveHdr[0].dwUser = waveHdr[1].dwUser = 0L; + waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L; + waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L; + waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize; + if (waveOutPrepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR)) || + waveOutPrepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR))) { + goto errCleanUp; + } + + s.dwEventCount = 1L; /* for first buffer */ + + do { + index = 0; + left = mmckInfo.cksize; + + mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET); + while (left) + { + if (WaitForSingleObject(WINMM_IData->psStopEvent, 0) == WAIT_OBJECT_0) + { + wps->bLoop = FALSE; + break; + } + count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left)); + if (count < 1) break; + left -= count; + waveHdr[index].dwBufferLength = count; + waveHdr[index].dwFlags &= ~WHDR_DONE; + if (waveOutWrite(hWave, &waveHdr[index], sizeof(WAVEHDR)) == MMSYSERR_NOERROR) { + index ^= 1; + PlaySound_WaitDone(&s); + } + else FIXME("Couldn't play header\n"); + } + bRet = TRUE; + } while (wps->bLoop); + + PlaySound_WaitDone(&s); /* for last buffer */ + waveOutReset(hWave); + + waveOutUnprepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR)); + waveOutUnprepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR)); + +errCleanUp: + TRACE("Done playing='%s' => %s!\n", debugstr_w(wps->pszSound), bRet ? "ok" : "ko"); + CloseHandle(s.hEvent); + if (waveHdr) HeapFree(GetProcessHeap(), 0, waveHdr); + if (lpWaveFormat) HeapFree(GetProcessHeap(), 0, lpWaveFormat); + if (hWave) while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100); + if (hmmio) mmioClose(hmmio, 0); + + PlaySound_Free(wps); + + return bRet; +} + +static BOOL MULTIMEDIA_PlaySound(const void* pszSound, HMODULE hmod, DWORD fdwSound, BOOL bUnicode) +{ + WINE_PLAYSOUND* wps = NULL; + + TRACE("pszSound='%p' hmod=%p fdwSound=%08lX\n", + pszSound, hmod, fdwSound); + + /* FIXME? I see no difference between SND_NOWAIT and SND_NOSTOP ! + * there could be one if several sounds can be played at once... + */ + if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && WINMM_IData->lpPlaySound != NULL) + return FALSE; + + /* alloc internal structure, if we need to play something */ + if (pszSound && !(fdwSound & SND_PURGE)) + { + if (!(wps = PlaySound_Alloc(pszSound, hmod, fdwSound, bUnicode))) + return FALSE; + } + + EnterCriticalSection(&WINMM_IData->cs); + /* since several threads can enter PlaySound in parallel, we're not + * sure, at this point, that another thread didn't start a new playsound + */ + while (WINMM_IData->lpPlaySound != NULL) + { + ResetEvent(WINMM_IData->psLastEvent); + /* FIXME: doc says we have to stop all instances of pszSound if it's non + * NULL... as of today, we stop all playing instances */ + SetEvent(WINMM_IData->psStopEvent); + + LeaveCriticalSection(&WINMM_IData->cs); + WaitForSingleObject(WINMM_IData->psLastEvent, INFINITE); + EnterCriticalSection(&WINMM_IData->cs); + + ResetEvent(WINMM_IData->psStopEvent); + } + + if (wps) wps->lpNext = WINMM_IData->lpPlaySound; + WINMM_IData->lpPlaySound = wps; + LeaveCriticalSection(&WINMM_IData->cs); + + if (!pszSound || (fdwSound & SND_PURGE)) return TRUE; + + if (fdwSound & SND_ASYNC) + { + DWORD id; + HANDLE handle; + wps->bLoop = (fdwSound & SND_LOOP) ? TRUE : FALSE; + if ((handle = CreateThread(NULL, 0, proc_PlaySound, wps, 0, &id)) != 0) { + wps->hThread = handle; + return TRUE; + } + } + else return proc_PlaySound(wps); + + /* error cases */ + PlaySound_Free(wps); + return FALSE; +} + +/************************************************************************** + * PlaySoundA [WINMM.@] + */ +BOOL WINAPI PlaySoundA(LPCSTR pszSoundA, HMODULE hmod, DWORD fdwSound) +{ + return MULTIMEDIA_PlaySound(pszSoundA, hmod, fdwSound, FALSE); +} + +/************************************************************************** + * PlaySoundW [WINMM.@] + */ +BOOL WINAPI PlaySoundW(LPCWSTR pszSoundW, HMODULE hmod, DWORD fdwSound) +{ + return MULTIMEDIA_PlaySound(pszSoundW, hmod, fdwSound, TRUE); +} + +/************************************************************************** + * sndPlaySoundA [WINMM.@] + */ +BOOL WINAPI sndPlaySoundA(LPCSTR pszSoundA, UINT uFlags) +{ + uFlags &= SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC; + return MULTIMEDIA_PlaySound(pszSoundA, 0, uFlags, FALSE); +} + +/************************************************************************** + * sndPlaySoundW [WINMM.@] + */ +BOOL WINAPI sndPlaySoundW(LPCWSTR pszSound, UINT uFlags) +{ + uFlags &= SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC; + return MULTIMEDIA_PlaySound(pszSound, 0, uFlags, TRUE); +} + +/************************************************************************** + * mmsystemGetVersion [WINMM.@] + */ +UINT WINAPI mmsystemGetVersion(void) +{ + TRACE("3.10 (Win95?)\n"); + return 0x030a; +} diff --git a/reactos/lib/winmm/sound.spec b/reactos/lib/winmm/sound.spec new file mode 100644 index 00000000000..a44fd1eec77 --- /dev/null +++ b/reactos/lib/winmm/sound.spec @@ -0,0 +1,18 @@ +1 pascal -ret16 OpenSound() OpenSound16 +2 pascal -ret16 CloseSound() CloseSound16 +3 pascal -ret16 SetVoiceQueueSize(word word) SetVoiceQueueSize16 +4 pascal -ret16 SetVoiceNote(word word word word) SetVoiceNote16 +5 pascal -ret16 SetVoiceAccent(word word word word word) SetVoiceAccent16 +6 pascal -ret16 SetVoiceEnvelope(word word word) SetVoiceEnvelope16 +7 pascal -ret16 SetSoundNoise(word word) SetSoundNoise16 +8 pascal -ret16 SetVoiceSound(word long word) SetVoiceSound16 +9 pascal -ret16 StartSound() StartSound16 +10 pascal -ret16 StopSound() StopSound16 +11 pascal -ret16 WaitSoundState(word) WaitSoundState16 +12 pascal -ret16 SyncAllVoices() SyncAllVoices16 +13 pascal -ret16 CountVoiceNotes(word) CountVoiceNotes16 +14 pascal GetThresholdEvent() GetThresholdEvent16 +15 pascal -ret16 GetThresholdStatus() GetThresholdStatus16 +16 pascal -ret16 SetVoiceThreshold(word word) SetVoiceThreshold16 +17 pascal -ret16 DoBeep() DoBeep16 +18 stub MYOPENSOUND # W1.1, W2.0 diff --git a/reactos/lib/winmm/sound16.c b/reactos/lib/winmm/sound16.c new file mode 100644 index 00000000000..1a670c92763 --- /dev/null +++ b/reactos/lib/winmm/sound16.c @@ -0,0 +1,184 @@ +/* + * 16-bit sound support + * + * Copyright Robert J. Amstadt, 1993 + * + * 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 +#include +#include "windef.h" +#include "winbase.h" +#include "wine/windef16.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(sound); + +/*********************************************************************** + * OpenSound (SOUND.1) + */ +INT16 WINAPI OpenSound16(void) +{ + FIXME("(void): stub\n"); + return -1; +} + +/*********************************************************************** + * CloseSound (SOUND.2) + */ +void WINAPI CloseSound16(void) +{ + FIXME("(void): stub\n"); +} + +/*********************************************************************** + * SetVoiceQueueSize (SOUND.3) + */ +INT16 WINAPI SetVoiceQueueSize16(INT16 nVoice, INT16 nBytes) +{ + FIXME("(%d,%d): stub\n",nVoice,nBytes); + return 0; +} + +/*********************************************************************** + * SetVoiceNote (SOUND.4) + */ +INT16 WINAPI SetVoiceNote16(INT16 nVoice, INT16 nValue, INT16 nLength, + INT16 nCdots) +{ + FIXME("(%d,%d,%d,%d): stub\n",nVoice,nValue,nLength,nCdots); + return 0; +} + +/*********************************************************************** + * SetVoiceAccent (SOUND.5) + */ +INT16 WINAPI SetVoiceAccent16(INT16 nVoice, INT16 nTempo, INT16 nVolume, + INT16 nMode, INT16 nPitch) +{ + FIXME("(%d,%d,%d,%d,%d): stub\n", nVoice, nTempo, + nVolume, nMode, nPitch); + return 0; +} + +/*********************************************************************** + * SetVoiceEnvelope (SOUND.6) + */ +INT16 WINAPI SetVoiceEnvelope16(INT16 nVoice, INT16 nShape, INT16 nRepeat) +{ + FIXME("(%d,%d,%d): stub\n",nVoice,nShape,nRepeat); + return 0; +} + +/*********************************************************************** + * SetSoundNoise (SOUND.7) + */ +INT16 WINAPI SetSoundNoise16(INT16 nSource, INT16 nDuration) +{ + FIXME("(%d,%d): stub\n",nSource,nDuration); + return 0; +} + +/*********************************************************************** + * SetVoiceSound (SOUND.8) + */ +INT16 WINAPI SetVoiceSound16(INT16 nVoice, DWORD lFrequency, INT16 nDuration) +{ + FIXME("(%d, %ld, %d): stub\n",nVoice,lFrequency, nDuration); + return 0; +} + +/*********************************************************************** + * StartSound (SOUND.9) + */ +INT16 WINAPI StartSound16(void) +{ + return 0; +} + +/*********************************************************************** + * StopSound (SOUND.10) + */ +INT16 WINAPI StopSound16(void) +{ + return 0; +} + +/*********************************************************************** + * WaitSoundState (SOUND.11) + */ +INT16 WINAPI WaitSoundState16(INT16 x) +{ + FIXME("(%d): stub\n", x); + return 0; +} + +/*********************************************************************** + * SyncAllVoices (SOUND.12) + */ +INT16 WINAPI SyncAllVoices16(void) +{ + FIXME("(void): stub\n"); + return 0; +} + +/*********************************************************************** + * CountVoiceNotes (SOUND.13) + */ +INT16 WINAPI CountVoiceNotes16(INT16 x) +{ + FIXME("(%d): stub\n", x); + return 0; +} + +/*********************************************************************** + * GetThresholdEvent (SOUND.14) + */ +LPINT16 WINAPI GetThresholdEvent16(void) +{ + FIXME("(void): stub\n"); + return NULL; +} + +/*********************************************************************** + * GetThresholdStatus (SOUND.15) + */ +INT16 WINAPI GetThresholdStatus16(void) +{ + FIXME("(void): stub\n"); + return 0; +} + +/*********************************************************************** + * SetVoiceThreshold (SOUND.16) + */ +INT16 WINAPI SetVoiceThreshold16(INT16 a, INT16 b) +{ + FIXME("(%d,%d): stub\n", a, b); + return 0; +} + +/*********************************************************************** + * DoBeep (SOUND.17) + */ +void WINAPI DoBeep16(void) +{ + FIXME("(void): stub!\n"); +} + + + + diff --git a/reactos/lib/winmm/time.c b/reactos/lib/winmm/time.c new file mode 100644 index 00000000000..ea8daef3697 --- /dev/null +++ b/reactos/lib/winmm/time.c @@ -0,0 +1,464 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/* + * MMSYSTEM time functions + * + * Copyright 1993 Martin Ayotte + * + * 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 "config.h" +#include "wine/port.h" + +#include +#include +#ifdef HAVE_SYS_TIME_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif + +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" + +#include "winemm.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mmtime); + +static HANDLE TIME_hMMTimer; +static LPWINE_TIMERENTRY TIME_TimersList; +static HANDLE TIME_hKillEvent; +static HANDLE TIME_hWakeEvent; +static BOOL TIME_TimeToDie = TRUE; + +/* + * Some observations on the behavior of winmm on Windows. + * First, the call to timeBeginPeriod(xx) can never be used + * to raise the timer resolution, only lower it. + * + * Second, a brief survey of a variety of Win 2k and Win X + * machines showed that a 'standard' (aka default) timer + * resolution was 1 ms (Win9x is documented as being 1). However, one + * machine had a standard timer resolution of 10 ms. + * + * Further, if we set our default resolution to 1, + * the implementation of timeGetTime becomes GetTickCount(), + * and we can optimize the code to reduce overhead. + * + * Additionally, a survey of Event behaviors shows that + * if we request a Periodic event every 50 ms, then Windows + * makes sure to trigger that event 20 times in the next + * second. If delays prevent that from happening on exact + * schedule, Windows will trigger the events as close + * to the original schedule as is possible, and will eventually + * bring the event triggers back onto a schedule that is + * consistent with what would have happened if there were + * no delays. + * + * Jeremy White, October 2004 + */ +#define MMSYSTIME_MININTERVAL (1) +#define MMSYSTIME_MAXINTERVAL (65535) + + +static void TIME_TriggerCallBack(LPWINE_TIMERENTRY lpTimer) +{ + TRACE("%04lx:CallBack => lpFunc=%p wTimerID=%04X dwUser=%08lX dwTriggerTime %ld(delta %ld)\n", + GetCurrentThreadId(), lpTimer->lpFunc, lpTimer->wTimerID, lpTimer->dwUser, + lpTimer->dwTriggerTime, GetTickCount() - lpTimer->dwTriggerTime); + + /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called + * during interrupt time, is allowed to execute very limited number of API calls (like + * PostMessage), and must reside in DLL (therefore uses stack of active application). So I + * guess current implementation via SetTimer has to be improved upon. + */ + switch (lpTimer->wFlags & 0x30) { + case TIME_CALLBACK_FUNCTION: + if (lpTimer->wFlags & WINE_TIMER_IS32) + (lpTimer->lpFunc)(lpTimer->wTimerID, 0, lpTimer->dwUser, 0, 0); + else if (pFnCallMMDrvFunc16) + pFnCallMMDrvFunc16((DWORD)lpTimer->lpFunc, lpTimer->wTimerID, 0, + lpTimer->dwUser, 0, 0); + break; + case TIME_CALLBACK_EVENT_SET: + SetEvent((HANDLE)lpTimer->lpFunc); + break; + case TIME_CALLBACK_EVENT_PULSE: + PulseEvent((HANDLE)lpTimer->lpFunc); + break; + default: + FIXME("Unknown callback type 0x%04x for mmtime callback (%p), ignored.\n", + lpTimer->wFlags, lpTimer->lpFunc); + break; + } +} + +/************************************************************************** + * TIME_MMSysTimeCallback + */ +static DWORD CALLBACK TIME_MMSysTimeCallback(LPWINE_MM_IDATA iData) +{ +static int nSizeLpTimers; +static LPWINE_TIMERENTRY lpTimers; + + LPWINE_TIMERENTRY timer, *ptimer, *next_ptimer; + int idx; + DWORD cur_time; + DWORD delta_time; + DWORD ret_time = INFINITE; + DWORD adjust_time; + + + /* optimize for the most frequent case - no events */ + if (! TIME_TimersList) + return(ret_time); + + /* since timeSetEvent() and timeKillEvent() can be called + * from 16 bit code, there are cases where win16 lock is + * locked upon entering timeSetEvent(), and then the mm timer + * critical section is locked. This function cannot call the + * timer callback with the crit sect locked (because callback + * may need to acquire Win16 lock, thus providing a deadlock + * situation). + * To cope with that, we just copy the WINE_TIMERENTRY struct + * that need to trigger the callback, and call it without the + * mm timer crit sect locked. + * the hKillTimeEvent is used to mark the section where we + * handle the callbacks so we can do synchronous kills. + * EPP 99/07/13, updated 04/01/10 + */ + idx = 0; + cur_time = GetTickCount(); + + EnterCriticalSection(&iData->cs); + for (ptimer = &TIME_TimersList; *ptimer != NULL; ) { + timer = *ptimer; + next_ptimer = &timer->lpNext; + if (cur_time >= timer->dwTriggerTime) + { + if (timer->lpFunc) { + if (idx == nSizeLpTimers) { + if (lpTimers) + lpTimers = (LPWINE_TIMERENTRY) + HeapReAlloc(GetProcessHeap(), 0, lpTimers, + ++nSizeLpTimers * sizeof(WINE_TIMERENTRY)); + else + lpTimers = (LPWINE_TIMERENTRY) + HeapAlloc(GetProcessHeap(), 0, + ++nSizeLpTimers * sizeof(WINE_TIMERENTRY)); + } + lpTimers[idx++] = *timer; + + } + + /* Update the time after we make the copy to preserve + the original trigger time */ + timer->dwTriggerTime += timer->wDelay; + + /* TIME_ONESHOT is defined as 0 */ + if (!(timer->wFlags & TIME_PERIODIC)) + { + /* unlink timer from timers list */ + *ptimer = *next_ptimer; + HeapFree(GetProcessHeap(), 0, timer); + + /* We don't need to trigger oneshots again */ + delta_time = INFINITE; + } + else + { + /* Compute when this event needs this function + to be called again */ + if (timer->dwTriggerTime <= cur_time) + delta_time = 0; + else + delta_time = timer->dwTriggerTime - cur_time; + } + } + else + delta_time = timer->dwTriggerTime - cur_time; + + /* Determine when we need to return to this function */ + ret_time = min(ret_time, delta_time); + + ptimer = next_ptimer; + } + if (TIME_hKillEvent) ResetEvent(TIME_hKillEvent); + LeaveCriticalSection(&iData->cs); + + while (idx > 0) TIME_TriggerCallBack(&lpTimers[--idx]); + if (TIME_hKillEvent) SetEvent(TIME_hKillEvent); + + /* Finally, adjust the recommended wait time downward + by the amount of time the processing routines + actually took */ + adjust_time = GetTickCount() - cur_time; + if (adjust_time > ret_time) + ret_time = 0; + else + ret_time -= adjust_time; + + /* We return the amount of time our caller should sleep + before needing to check in on us again */ + return(ret_time); +} + +/************************************************************************** + * TIME_MMSysTimeThread + */ +static DWORD CALLBACK TIME_MMSysTimeThread(LPVOID arg) +{ + LPWINE_MM_IDATA iData = (LPWINE_MM_IDATA)arg; + DWORD sleep_time; + DWORD rc; + + TRACE("Starting main winmm thread\n"); + + /* FIXME: As an optimization, we could have + this thread die when there are no more requests + pending, and then get recreated on the first + new event; it's not clear if that would be worth + it or not. */ + + while (! TIME_TimeToDie) + { + sleep_time = TIME_MMSysTimeCallback(iData); + + if (sleep_time == 0) + continue; + + rc = WaitForSingleObject(TIME_hWakeEvent, sleep_time); + if (rc != WAIT_TIMEOUT && rc != WAIT_OBJECT_0) + { + FIXME("Unexpected error %ld(%ld) in timer thread\n", rc, GetLastError()); + break; + } + } + TRACE("Exiting main winmm thread\n"); + return 0; +} + +/************************************************************************** + * TIME_MMTimeStart + */ +void TIME_MMTimeStart(void) +{ + if (!TIME_hMMTimer) { + TIME_TimersList = NULL; + TIME_hWakeEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + TIME_TimeToDie = FALSE; + TIME_hMMTimer = CreateThread(NULL, 0, TIME_MMSysTimeThread, WINMM_IData, 0, NULL); + } +} + +/************************************************************************** + * TIME_MMTimeStop + */ +void TIME_MMTimeStop(void) +{ + if (TIME_hMMTimer) { + + TIME_TimeToDie = TRUE; + SetEvent(TIME_hWakeEvent); + + /* FIXME: in the worst case, we're going to wait 65 seconds here :-( */ + WaitForSingleObject(TIME_hMMTimer, INFINITE); + + CloseHandle(TIME_hMMTimer); + CloseHandle(TIME_hWakeEvent); + TIME_hMMTimer = 0; + TIME_TimersList = NULL; + } +} + +/************************************************************************** + * timeGetSystemTime [WINMM.@] + */ +MMRESULT WINAPI timeGetSystemTime(LPMMTIME lpTime, UINT wSize) +{ + + if (wSize >= sizeof(*lpTime)) { + lpTime->wType = TIME_MS; + lpTime->u.ms = GetTickCount(); + + } + + return 0; +} + +/************************************************************************** + * TIME_SetEventInternal [internal] + */ +WORD TIME_SetEventInternal(UINT wDelay, UINT wResol, + LPTIMECALLBACK lpFunc, DWORD dwUser, UINT wFlags) +{ + WORD wNewID = 0; + LPWINE_TIMERENTRY lpNewTimer; + LPWINE_TIMERENTRY lpTimer; + + TRACE("(%u, %u, %p, %08lX, %04X);\n", wDelay, wResol, lpFunc, dwUser, wFlags); + + lpNewTimer = (LPWINE_TIMERENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_TIMERENTRY)); + if (lpNewTimer == NULL) + return 0; + + if (wDelay < MMSYSTIME_MININTERVAL || wDelay > MMSYSTIME_MAXINTERVAL) + return 0; + + TIME_MMTimeStart(); + + lpNewTimer->wDelay = wDelay; + lpNewTimer->dwTriggerTime = GetTickCount() + wDelay; + + /* FIXME - wResol is not respected, although it is not clear + that we could change our precision meaningfully */ + lpNewTimer->wResol = wResol; + lpNewTimer->lpFunc = lpFunc; + lpNewTimer->dwUser = dwUser; + lpNewTimer->wFlags = wFlags; + + EnterCriticalSection(&WINMM_IData->cs); + + if ((wFlags & TIME_KILL_SYNCHRONOUS) && !TIME_hKillEvent) + TIME_hKillEvent = CreateEventW(NULL, TRUE, TRUE, NULL); + + for (lpTimer = TIME_TimersList; lpTimer != NULL; lpTimer = lpTimer->lpNext) { + wNewID = max(wNewID, lpTimer->wTimerID); + } + + lpNewTimer->lpNext = TIME_TimersList; + TIME_TimersList = lpNewTimer; + lpNewTimer->wTimerID = wNewID + 1; + + LeaveCriticalSection(&WINMM_IData->cs); + + /* Wake the service thread in case there is work to be done */ + SetEvent(TIME_hWakeEvent); + + TRACE("=> %u\n", wNewID + 1); + + return wNewID + 1; +} + +/************************************************************************** + * timeSetEvent [WINMM.@] + */ +MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc, + DWORD_PTR dwUser, UINT wFlags) +{ + if (wFlags & WINE_TIMER_IS32) + WARN("Unknown windows flag... wine internally used.. ooch\n"); + + return TIME_SetEventInternal(wDelay, wResol, lpFunc, + dwUser, wFlags|WINE_TIMER_IS32); +} + +/************************************************************************** + * timeKillEvent [WINMM.@] + */ +MMRESULT WINAPI timeKillEvent(UINT wID) +{ + LPWINE_TIMERENTRY lpSelf = NULL, *lpTimer; + + TRACE("(%u)\n", wID); + EnterCriticalSection(&WINMM_IData->cs); + /* remove WINE_TIMERENTRY from list */ + for (lpTimer = &TIME_TimersList; *lpTimer; lpTimer = &(*lpTimer)->lpNext) { + if (wID == (*lpTimer)->wTimerID) { + lpSelf = *lpTimer; + /* unlink timer of id 'wID' */ + *lpTimer = (*lpTimer)->lpNext; + break; + } + } + LeaveCriticalSection(&WINMM_IData->cs); + + if (!lpSelf) + { + WARN("wID=%u is not a valid timer ID\n", wID); + return MMSYSERR_INVALPARAM; + } + if (lpSelf->wFlags & TIME_KILL_SYNCHRONOUS) + WaitForSingleObject(TIME_hKillEvent, INFINITE); + HeapFree(GetProcessHeap(), 0, lpSelf); + return TIMERR_NOERROR; +} + +/************************************************************************** + * timeGetDevCaps [WINMM.@] + */ +MMRESULT WINAPI timeGetDevCaps(LPTIMECAPS lpCaps, UINT wSize) +{ + TRACE("(%p, %u)\n", lpCaps, wSize); + + lpCaps->wPeriodMin = MMSYSTIME_MININTERVAL; + lpCaps->wPeriodMax = MMSYSTIME_MAXINTERVAL; + return 0; +} + +/************************************************************************** + * timeBeginPeriod [WINMM.@] + */ +MMRESULT WINAPI timeBeginPeriod(UINT wPeriod) +{ + if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL) + return TIMERR_NOCANDO; + + if (wPeriod > MMSYSTIME_MININTERVAL) + { + FIXME("Stub; we set our timer resolution at minimum\n"); + } + + return 0; +} + +/************************************************************************** + * timeEndPeriod [WINMM.@] + */ +MMRESULT WINAPI timeEndPeriod(UINT wPeriod) +{ + if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL) + return TIMERR_NOCANDO; + + if (wPeriod > MMSYSTIME_MININTERVAL) + { + FIXME("Stub; we set our timer resolution at minimum\n"); + } + return 0; +} + +/************************************************************************** + * timeGetTime [MMSYSTEM.607] + * timeGetTime [WINMM.@] + */ +DWORD WINAPI timeGetTime(void) +{ +#if defined(COMMENTOUTPRIORTODELETING) + DWORD count; + + /* FIXME: releasing the win16 lock here is a temporary hack (I hope) + * that lets mciavi.drv run correctly + */ + if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count); + if (pFnRestoreThunkLock) pFnRestoreThunkLock(count); +#endif + + return GetTickCount(); +} diff --git a/reactos/lib/winmm/wavemap/.cvsignore b/reactos/lib/winmm/wavemap/.cvsignore new file mode 100644 index 00000000000..d57696a1f81 --- /dev/null +++ b/reactos/lib/winmm/wavemap/.cvsignore @@ -0,0 +1,2 @@ +Makefile +msacm.drv.dbg.c diff --git a/reactos/lib/winmm/wavemap/Makefile.in b/reactos/lib/winmm/wavemap/Makefile.in new file mode 100644 index 00000000000..071f5f84d7a --- /dev/null +++ b/reactos/lib/winmm/wavemap/Makefile.in @@ -0,0 +1,13 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = msacm.drv +IMPORTS = msacm32 winmm user32 kernel32 + +C_SRCS = \ + wavemap.c + +@MAKE_DLL_RULES@ + +### Dependencies: diff --git a/reactos/lib/winmm/wavemap/Makefile.ros-template b/reactos/lib/winmm/wavemap/Makefile.ros-template new file mode 100644 index 00000000000..96c5a52f7fd --- /dev/null +++ b/reactos/lib/winmm/wavemap/Makefile.ros-template @@ -0,0 +1,23 @@ +# $Id: Makefile.ros-template 11910 2004-12-03 23:37:44Z blight $ + +TARGET_NAME = msacm + +TARGET_OBJECTS = @C_SRCS@ + +TARGET_CFLAGS = @EXTRADEFS@ -D__REACTOS__ + +TARGET_SDKLIBS = @IMPORTS@ winmm.a wine.a wine_uuid.a ntdll.a + +TARGET_BASE = 0x76160000 + +TARGET_RC_SRCS = wavemap.rc +TARGET_RC_BINSRC = @RC_BINSRC@ +TARGET_RC_BINARIES = @RC_BINARIES@ + +TARGET_EXTENSION = .drv + +default: all + +DEP_OBJECTS = $(TARGET_OBJECTS) + +include $(TOOLS_PATH)/depend.mk diff --git a/reactos/lib/winmm/wavemap/makefile b/reactos/lib/winmm/wavemap/makefile new file mode 100644 index 00000000000..11941603f41 --- /dev/null +++ b/reactos/lib/winmm/wavemap/makefile @@ -0,0 +1,9 @@ +# $Id: makefile 8620 2004-03-10 15:22:45Z silverblade $ + +PATH_TO_TOP = ../../.. + +TARGET_TYPE = winedll + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk diff --git a/reactos/lib/winmm/wavemap/msacm.drv.spec b/reactos/lib/winmm/wavemap/msacm.drv.spec new file mode 100644 index 00000000000..86707d8055a --- /dev/null +++ b/reactos/lib/winmm/wavemap/msacm.drv.spec @@ -0,0 +1,3 @@ +@ stdcall DriverProc(long long long long long) WAVEMAP_DriverProc +@ stdcall widMessage(long long long long long) WAVEMAP_widMessage +@ stdcall wodMessage(long long long long long) WAVEMAP_wodMessage diff --git a/reactos/lib/winmm/wavemap/msacm.spec b/reactos/lib/winmm/wavemap/msacm.spec new file mode 100644 index 00000000000..86707d8055a --- /dev/null +++ b/reactos/lib/winmm/wavemap/msacm.spec @@ -0,0 +1,3 @@ +@ stdcall DriverProc(long long long long long) WAVEMAP_DriverProc +@ stdcall widMessage(long long long long long) WAVEMAP_widMessage +@ stdcall wodMessage(long long long long long) WAVEMAP_wodMessage diff --git a/reactos/lib/winmm/wavemap/wavemap.c b/reactos/lib/winmm/wavemap/wavemap.c new file mode 100644 index 00000000000..6dc55867aec --- /dev/null +++ b/reactos/lib/winmm/wavemap/wavemap.c @@ -0,0 +1,1101 @@ +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ +/* + * Wine Wave mapper driver + * + * Copyright 1999,2001 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 + */ + +/* TODOs + * + better protection against evilish dwUser parameters + * + use asynchronous ACM conversion + * + don't use callback functions when none is required in open + * + the buffer sizes may not be accurate, so there may be some + * remaining bytes in src and dst buffers after ACM conversions... + * those should be taken care of... + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "mmddk.h" +#include "mmreg.h" +#include "msacm.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wavemap); + +typedef struct tagWAVEMAPDATA { + struct tagWAVEMAPDATA* self; + union { + struct { + HWAVEOUT hOuterWave; + HWAVEOUT hInnerWave; + } out; + struct { + HWAVEIN hOuterWave; + HWAVEIN hInnerWave; + } in; + } u; + HACMSTREAM hAcmStream; + /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */ + DWORD dwCallback; + DWORD dwClientInstance; + DWORD dwFlags; + /* ratio to compute position from a PCM playback to any format */ + DWORD avgSpeedOuter; + DWORD avgSpeedInner; +} WAVEMAPDATA; + +static BOOL WAVEMAP_IsData(WAVEMAPDATA* wm) +{ + return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm); +} + +/*======================================================================* + * WAVE OUT part * + *======================================================================*/ + +static void CALLBACK wodCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwInstance, + DWORD dwParam1, DWORD dwParam2) +{ + WAVEMAPDATA* wom = (WAVEMAPDATA*)dwInstance; + + TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2); + + if (!WAVEMAP_IsData(wom)) { + ERR("Bad data\n"); + return; + } + + if (hWave != wom->u.out.hInnerWave && uMsg != WOM_OPEN) + ERR("Shouldn't happen (%p %p)\n", hWave, wom->u.out.hInnerWave); + + switch (uMsg) { + case WOM_OPEN: + case WOM_CLOSE: + /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ + break; + case WOM_DONE: + if (wom->hAcmStream) { + LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)dwParam1; + PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER)); + LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser; + + lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE; + lpWaveHdrSrc->dwFlags |= WHDR_DONE; + dwParam1 = (DWORD)lpWaveHdrSrc; + } + break; + default: + ERR("Unknown msg %u\n", uMsg); + } + + DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), (HDRVR)wom->u.out.hOuterWave, + uMsg, wom->dwClientInstance, dwParam1, dwParam2); +} + +/****************************************************************** + * wodOpenHelper + * + * + */ +static DWORD wodOpenHelper(WAVEMAPDATA* wom, UINT idx, + LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx, + DWORD dwFlags) +{ + DWORD ret; + + TRACE("(%p %04x %p %p %08lx)\n", wom, idx, lpDesc, lpwfx, dwFlags); + + /* destination is always PCM, so the formulas below apply */ + lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8; + lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign; + if (dwFlags & WAVE_FORMAT_QUERY) { + ret = acmStreamOpen(NULL, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY); + } else { + ret = acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 0L); + } + if (ret == MMSYSERR_NOERROR) { + ret = waveOutOpen(&wom->u.out.hInnerWave, idx, lpwfx, (DWORD)wodCallback, + (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION); + if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) { + acmStreamClose(wom->hAcmStream, 0); + wom->hAcmStream = 0; + } + } + TRACE("ret = %08lx\n", ret); + return ret; +} + +static DWORD wodOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags) +{ + UINT ndlo, ndhi; + UINT i; + WAVEMAPDATA* wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA)); + DWORD res; + + TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags); + + if (!wom) { + WARN("no memory\n"); + return MMSYSERR_NOMEM; + } + + ndhi = waveOutGetNumDevs(); + if (dwFlags & WAVE_MAPPED) { + if (lpDesc->uMappedDeviceID >= ndhi) { + WARN("invalid parameter: dwFlags WAVE_MAPPED\n"); + return MMSYSERR_INVALPARAM; + } + ndlo = lpDesc->uMappedDeviceID; + ndhi = ndlo + 1; + dwFlags &= ~WAVE_MAPPED; + } else { + ndlo = 0; + } + wom->self = wom; + wom->dwCallback = lpDesc->dwCallback; + wom->dwFlags = dwFlags; + wom->dwClientInstance = lpDesc->dwInstance; + wom->u.out.hOuterWave = (HWAVEOUT)lpDesc->hWave; + wom->avgSpeedOuter = wom->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec; + + for (i = ndlo; i < ndhi; i++) { + /* if no ACM stuff is involved, no need to handle callbacks at this + * level, this will be done transparently + */ + if (waveOutOpen(&wom->u.out.hInnerWave, i, lpDesc->lpFormat, (DWORD)wodCallback, + (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) { + wom->hAcmStream = 0; + goto found; + } + } + + if ((dwFlags & WAVE_FORMAT_DIRECT) == 0 && lpDesc->lpFormat->wFormatTag == WAVE_FORMAT_PCM) { + WAVEFORMATEX wfx; + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */ + /* try some ACM stuff */ + +#define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \ + switch (res=wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \ + case MMSYSERR_NOERROR: wom->avgSpeedInner = wfx.nAvgBytesPerSec; goto found; \ + case WAVERR_BADFORMAT: break; \ + default: goto error; \ + } + + /* Our resampling algorithm is quite primitive so first try + * to just change the bit depth and number of channels + */ + for (i = ndlo; i < ndhi; i++) { + wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; + wfx.nChannels = lpDesc->lpFormat->nChannels; + TRY(wfx.nSamplesPerSec, 16); + TRY(wfx.nSamplesPerSec, 8); + wfx.nChannels ^= 3; + TRY(wfx.nSamplesPerSec, 16); + TRY(wfx.nSamplesPerSec, 8); + } + + for (i = ndlo; i < ndhi; i++) { + /* first try with same stereo/mono option as source */ + wfx.nChannels = lpDesc->lpFormat->nChannels; + TRY(96000, 16); + TRY(48000, 16); + TRY(44100, 16); + TRY(22050, 16); + TRY(11025, 16); + + /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ + wfx.nChannels ^= 3; + TRY(96000, 16); + TRY(48000, 16); + TRY(44100, 16); + TRY(22050, 16); + TRY(11025, 16); + + /* first try with same stereo/mono option as source */ + wfx.nChannels = lpDesc->lpFormat->nChannels; + TRY(96000, 8); + TRY(48000, 8); + TRY(44100, 8); + TRY(22050, 8); + TRY(11025, 8); + + /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ + wfx.nChannels ^= 3; + TRY(96000, 8); + TRY(48000, 8); + TRY(44100, 8); + TRY(22050, 8); + TRY(11025, 8); + } +#undef TRY + } + + HeapFree(GetProcessHeap(), 0, wom); + WARN("ret = WAVERR_BADFORMAT\n"); + return WAVERR_BADFORMAT; + +found: + if (dwFlags & WAVE_FORMAT_QUERY) { + *lpdwUser = 0L; + HeapFree(GetProcessHeap(), 0, wom); + } else { + *lpdwUser = (DWORD)wom; + } + return MMSYSERR_NOERROR; +error: + HeapFree(GetProcessHeap(), 0, wom); + if (res==ACMERR_NOTPOSSIBLE) { + WARN("ret = WAVERR_BADFORMAT\n"); + return WAVERR_BADFORMAT; + } + WARN("ret = MMSYSERR_ERROR\n"); + return MMSYSERR_ERROR; +} + +static DWORD wodClose(WAVEMAPDATA* wom) +{ + DWORD ret; + + TRACE("(%p)\n", wom); + + ret = waveOutClose(wom->u.out.hInnerWave); + if (ret == MMSYSERR_NOERROR) { + if (wom->hAcmStream) { + ret = acmStreamClose(wom->hAcmStream, 0); + } + if (ret == MMSYSERR_NOERROR) { + HeapFree(GetProcessHeap(), 0, wom); + } + } + return ret; +} + +static DWORD wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) +{ + PACMSTREAMHEADER ash; + LPWAVEHDR lpWaveHdrDst; + + TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2); + + if (!wom->hAcmStream) { + return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2); + } + + lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE; + ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved; + /* acmStreamConvert will actually check that the new size is less than initial size */ + ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength; + if (acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) { + WARN("acmStreamConvert failed\n"); + return MMSYSERR_ERROR; + } + + lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); + if (ash->cbSrcLength > ash->cbSrcLengthUsed) + FIXME("Not all src buffer has been written, expect bogus sound\n"); + else if (ash->cbSrcLength < ash->cbSrcLengthUsed) + ERR("CoDec has read more data than it is allowed to\n"); + + if (ash->cbDstLengthUsed == 0) { + /* something went wrong in decoding */ + FIXME("Got 0 length\n"); + return MMSYSERR_ERROR; + } + lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed; + return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst)); +} + +static DWORD wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) +{ + PACMSTREAMHEADER ash; + DWORD size; + DWORD dwRet; + LPWAVEHDR lpWaveHdrDst; + + TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2); + + if (!wom->hAcmStream) + return waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2); + + if (acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR) { + WARN("acmStreamSize failed\n"); + return MMSYSERR_ERROR; + } + + ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size); + if (ash == NULL) { + WARN("no memory\n"); + return MMSYSERR_NOMEM; + } + + ash->cbStruct = sizeof(*ash); + ash->fdwStatus = 0L; + ash->dwUser = (DWORD)lpWaveHdrSrc; + ash->pbSrc = lpWaveHdrSrc->lpData; + ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength; + /* ash->cbSrcLengthUsed */ + ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */ + ash->pbDst = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR); + ash->cbDstLength = size; + /* ash->cbDstLengthUsed */ + ash->dwDstUser = 0; /* FIXME ? */ + dwRet = acmStreamPrepareHeader(wom->hAcmStream, ash, 0L); + if (dwRet != MMSYSERR_NOERROR) { + WARN("acmStreamPrepareHeader failed\n"); + goto errCleanUp; + } + + lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); + lpWaveHdrDst->lpData = ash->pbDst; + lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */ + lpWaveHdrDst->dwFlags = 0; + lpWaveHdrDst->dwLoops = 0; + dwRet = waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst)); + if (dwRet != MMSYSERR_NOERROR) { + WARN("waveOutPrepareHeader failed\n"); + goto errCleanUp; + } + + lpWaveHdrSrc->reserved = (DWORD)ash; + lpWaveHdrSrc->dwFlags = WHDR_PREPARED; + TRACE("=> (0)\n"); + return MMSYSERR_NOERROR; +errCleanUp: + TRACE("=> (%ld)\n", dwRet); + HeapFree(GetProcessHeap(), 0, ash); + return dwRet; +} + +static DWORD wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) +{ + PACMSTREAMHEADER ash; + LPWAVEHDR lpWaveHdrDst; + DWORD dwRet1, dwRet2; + + TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2); + + if (!wom->hAcmStream) { + return waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2); + } + ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved; + dwRet1 = acmStreamUnprepareHeader(wom->hAcmStream, ash, 0L); + + lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); + dwRet2 = waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst)); + + HeapFree(GetProcessHeap(), 0, ash); + + lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED; + return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1; +} + +static DWORD wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2) +{ + DWORD val; + TRACE("(%p %p %08lx)\n", wom, lpTime, dwParam2); + + val = waveOutGetPosition(wom->u.out.hInnerWave, lpTime, dwParam2); + if (lpTime->wType == TIME_BYTES) + lpTime->u.cb = MulDiv(lpTime->u.cb, wom->avgSpeedOuter, wom->avgSpeedInner); + /* other time types don't require conversion */ + return val; +} + +static DWORD wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSA lpWaveCaps, DWORD dwParam2) +{ + TRACE("(%04x %p %p %08lx)\n",wDevID, wom, lpWaveCaps, dwParam2); + + /* if opened low driver, forward message */ + if (WAVEMAP_IsData(wom)) + return waveOutGetDevCapsA((UINT)wom->u.out.hInnerWave, lpWaveCaps, dwParam2); + /* else if no drivers, nothing to map so return bad device */ + if (waveOutGetNumDevs() == 0) { + WARN("bad device id\n"); + return MMSYSERR_BADDEVICEID; + } + /* otherwise, return caps of mapper itself */ + if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) { + WAVEOUTCAPSA woc; + woc.wMid = 0x00FF; + woc.wPid = 0x0001; + woc.vDriverVersion = 0x0100; + strcpy(woc.szPname, "Wine wave out mapper"); + woc.dwFormats = + WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 | + WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | + WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 | + WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | + WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16; + woc.wChannels = 2; + woc.dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME; + memcpy(lpWaveCaps, &woc, min(dwParam2, sizeof(woc))); + + return MMSYSERR_NOERROR; + } + ERR("This shouldn't happen\n"); + return MMSYSERR_ERROR; +} + +static DWORD wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol) +{ + TRACE("(%04x %p %p)\n",wDevID, wom, lpVol); + + if (WAVEMAP_IsData(wom)) + return waveOutGetVolume(wom->u.out.hInnerWave, lpVol); + return MMSYSERR_NOERROR; +} + +static DWORD wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol) +{ + TRACE("(%04x %p %08lx)\n",wDevID, wom, vol); + + if (WAVEMAP_IsData(wom)) + return waveOutSetVolume(wom->u.out.hInnerWave, vol); + return MMSYSERR_NOERROR; +} + +static DWORD wodPause(WAVEMAPDATA* wom) +{ + TRACE("(%p)\n",wom); + + return waveOutPause(wom->u.out.hInnerWave); +} + +static DWORD wodRestart(WAVEMAPDATA* wom) +{ + TRACE("(%p)\n",wom); + + return waveOutRestart(wom->u.out.hInnerWave); +} + +static DWORD wodReset(WAVEMAPDATA* wom) +{ + TRACE("(%p)\n",wom); + + return waveOutReset(wom->u.out.hInnerWave); +} + +static DWORD wodBreakLoop(WAVEMAPDATA* wom) +{ + TRACE("(%p)\n",wom); + + return waveOutBreakLoop(wom->u.out.hInnerWave); +} + +static DWORD wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr) +{ + UINT id; + DWORD ret = MMSYSERR_NOTSUPPORTED; + + TRACE("(%p %08lx %p)\n",wom, flags, ptr); + + switch (flags) { + case WAVEOUT_MAPPER_STATUS_DEVICE: + ret = waveOutGetID(wom->u.out.hInnerWave, &id); + *(LPDWORD)ptr = id; + break; + case WAVEOUT_MAPPER_STATUS_MAPPED: + FIXME("Unsupported flag=%ld\n", flags); + *(LPDWORD)ptr = 0; /* FIXME ?? */ + break; + case WAVEOUT_MAPPER_STATUS_FORMAT: + FIXME("Unsupported flag=%ld\n", flags); + /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */ + *(LPDWORD)ptr = 0; + break; + default: + FIXME("Unsupported flag=%ld\n", flags); + *(LPDWORD)ptr = 0; + break; + } + return ret; +} + +/************************************************************************** + * wodMessage (MSACM.@) + */ +DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser, + DWORD dwParam1, DWORD dwParam2) +{ + TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n", + wDevID, wMsg, dwUser, dwParam1, dwParam2); + + switch (wMsg) { + case DRVM_INIT: + case DRVM_EXIT: + case DRVM_ENABLE: + case DRVM_DISABLE: + /* FIXME: Pretend this is supported */ + return 0; + case WODM_OPEN: return wodOpen ((LPDWORD)dwUser, (LPWAVEOPENDESC)dwParam1,dwParam2); + case WODM_CLOSE: return wodClose ((WAVEMAPDATA*)dwUser); + case WODM_WRITE: return wodWrite ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); + case WODM_PAUSE: return wodPause ((WAVEMAPDATA*)dwUser); + case WODM_GETPOS: return wodGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2); + case WODM_BREAKLOOP: return wodBreakLoop ((WAVEMAPDATA*)dwUser); + case WODM_PREPARE: return wodPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); + case WODM_UNPREPARE: return wodUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); + case WODM_GETDEVCAPS: return wodGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSA)dwParam1,dwParam2); + case WODM_GETNUMDEVS: return 1; + case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED; + case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED; + case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; + case WODM_SETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; + case WODM_GETVOLUME: return wodGetVolume (wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1); + case WODM_SETVOLUME: return wodSetVolume (wDevID, (WAVEMAPDATA*)dwUser, dwParam1); + case WODM_RESTART: return wodRestart ((WAVEMAPDATA*)dwUser); + case WODM_RESET: return wodReset ((WAVEMAPDATA*)dwUser); + case WODM_MAPPER_STATUS: return wodMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2); + /* known but not supported */ + case DRV_QUERYDEVICEINTERFACESIZE: + case DRV_QUERYDEVICEINTERFACE: + return MMSYSERR_NOTSUPPORTED; + default: + FIXME("unknown message %d!\n", wMsg); + } + return MMSYSERR_NOTSUPPORTED; +} + +/*======================================================================* + * WAVE IN part * + *======================================================================*/ + +static void CALLBACK widCallback(HWAVEIN hWave, UINT uMsg, DWORD dwInstance, + DWORD dwParam1, DWORD dwParam2) +{ + WAVEMAPDATA* wim = (WAVEMAPDATA*)dwInstance; + + TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2); + + if (!WAVEMAP_IsData(wim)) { + ERR("Bad data\n"); + return; + } + + if (hWave != wim->u.in.hInnerWave && uMsg != WIM_OPEN) + ERR("Shouldn't happen (%p %p)\n", hWave, wim->u.in.hInnerWave); + + switch (uMsg) { + case WIM_OPEN: + case WIM_CLOSE: + /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ + break; + case WIM_DATA: + if (wim->hAcmStream) { + LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)dwParam1; + PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrSrc - sizeof(ACMSTREAMHEADER)); + LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)ash->dwUser; + + /* convert data just gotten from waveIn into requested format */ + if (acmStreamConvert(wim->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) { + ERR("ACM conversion failed\n"); + return; + } else { + TRACE("Converted %ld bytes into %ld\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed); + } + /* and setup the wavehdr to return accordingly */ + lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE; + lpWaveHdrDst->dwFlags |= WHDR_DONE; + lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed; + dwParam1 = (DWORD)lpWaveHdrDst; + } + break; + default: + ERR("Unknown msg %u\n", uMsg); + } + + DriverCallback(wim->dwCallback, HIWORD(wim->dwFlags), (HDRVR)wim->u.in.hOuterWave, + uMsg, wim->dwClientInstance, dwParam1, dwParam2); +} + +static DWORD widOpenHelper(WAVEMAPDATA* wim, UINT idx, + LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx, + DWORD dwFlags) +{ + DWORD ret; + + TRACE("(%p %04x %p %p %08lx)\n", wim, idx, lpDesc, lpwfx, dwFlags); + + /* source is always PCM, so the formulas below apply */ + lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8; + lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign; + if (dwFlags & WAVE_FORMAT_QUERY) { + ret = acmStreamOpen(NULL, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY); + } else { + ret = acmStreamOpen(&wim->hAcmStream, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, 0L); + } + if (ret == MMSYSERR_NOERROR) { + ret = waveInOpen(&wim->u.in.hInnerWave, idx, lpwfx, (DWORD)widCallback, + (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION); + if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) { + acmStreamClose(wim->hAcmStream, 0); + wim->hAcmStream = 0; + } + } + TRACE("ret = %08lx\n", ret); + return ret; +} + +static DWORD widOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags) +{ + UINT ndlo, ndhi; + UINT i; + WAVEMAPDATA* wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA)); + DWORD res; + + TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags); + + if (!wim) { + WARN("no memory\n"); + return MMSYSERR_NOMEM; + } + + wim->self = wim; + wim->dwCallback = lpDesc->dwCallback; + wim->dwFlags = dwFlags; + wim->dwClientInstance = lpDesc->dwInstance; + wim->u.in.hOuterWave = (HWAVEIN)lpDesc->hWave; + + ndhi = waveInGetNumDevs(); + if (dwFlags & WAVE_MAPPED) { + if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM; + ndlo = lpDesc->uMappedDeviceID; + ndhi = ndlo + 1; + dwFlags &= ~WAVE_MAPPED; + } else { + ndlo = 0; + } + + wim->avgSpeedOuter = wim->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec; + + for (i = ndlo; i < ndhi; i++) { + if (waveInOpen(&wim->u.in.hInnerWave, i, lpDesc->lpFormat, (DWORD)widCallback, + (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) { + wim->hAcmStream = 0; + goto found; + } + } + + if ((dwFlags & WAVE_FORMAT_DIRECT) == 0) + { + WAVEFORMATEX wfx; + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */ + /* try some ACM stuff */ + +#define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \ + switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \ + case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; goto found; \ + case WAVERR_BADFORMAT: break; \ + default: goto error; \ + } + + for (i = ndlo; i < ndhi; i++) { + wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; + /* first try with same stereo/mono option as source */ + wfx.nChannels = lpDesc->lpFormat->nChannels; + TRY(wfx.nSamplesPerSec, 16); + TRY(wfx.nSamplesPerSec, 8); + wfx.nChannels ^= 3; + TRY(wfx.nSamplesPerSec, 16); + TRY(wfx.nSamplesPerSec, 8); + } + + for (i = ndlo; i < ndhi; i++) { + wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; + /* first try with same stereo/mono option as source */ + wfx.nChannels = lpDesc->lpFormat->nChannels; + TRY(96000, 16); + TRY(48000, 16); + TRY(44100, 16); + TRY(22050, 16); + TRY(11025, 16); + + /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ + wfx.nChannels ^= 3; + TRY(96000, 16); + TRY(48000, 16); + TRY(44100, 16); + TRY(22050, 16); + TRY(11025, 16); + + /* first try with same stereo/mono option as source */ + wfx.nChannels = lpDesc->lpFormat->nChannels; + TRY(96000, 8); + TRY(48000, 8); + TRY(44100, 8); + TRY(22050, 8); + TRY(11025, 8); + + /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ + wfx.nChannels ^= 3; + TRY(96000, 8); + TRY(48000, 8); + TRY(44100, 8); + TRY(22050, 8); + TRY(11025, 8); + } +#undef TRY + } + + HeapFree(GetProcessHeap(), 0, wim); + WARN("ret = WAVERR_BADFORMAT\n"); + return WAVERR_BADFORMAT; +found: + if (dwFlags & WAVE_FORMAT_QUERY) { + *lpdwUser = 0L; + HeapFree(GetProcessHeap(), 0, wim); + } else { + *lpdwUser = (DWORD)wim; + } + TRACE("Ok (stream=%08lx)\n", (DWORD)wim->hAcmStream); + return MMSYSERR_NOERROR; +error: + HeapFree(GetProcessHeap(), 0, wim); + if (res==ACMERR_NOTPOSSIBLE) { + WARN("ret = WAVERR_BADFORMAT\n"); + return WAVERR_BADFORMAT; + } + WARN("ret = MMSYSERR_ERROR\n"); + return MMSYSERR_ERROR; +} + +static DWORD widClose(WAVEMAPDATA* wim) +{ + DWORD ret; + + TRACE("(%p)\n", wim); + + ret = waveInClose(wim->u.in.hInnerWave); + if (ret == MMSYSERR_NOERROR) { + if (wim->hAcmStream) { + ret = acmStreamClose(wim->hAcmStream, 0); + } + if (ret == MMSYSERR_NOERROR) { + HeapFree(GetProcessHeap(), 0, wim); + } + } + return ret; +} + +static DWORD widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) +{ + PACMSTREAMHEADER ash; + LPWAVEHDR lpWaveHdrSrc; + + TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2); + + if (!wim->hAcmStream) { + return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); + } + + lpWaveHdrDst->dwFlags |= WHDR_INQUEUE; + ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved; + + lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); + return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); +} + +static DWORD widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) +{ + PACMSTREAMHEADER ash; + DWORD size; + DWORD dwRet; + LPWAVEHDR lpWaveHdrSrc; + + TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2); + + if (!wim->hAcmStream) { + return waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); + } + if (acmStreamSize(wim->hAcmStream, lpWaveHdrDst->dwBufferLength, &size, + ACM_STREAMSIZEF_DESTINATION) != MMSYSERR_NOERROR) { + WARN("acmStreamSize failed\n"); + return MMSYSERR_ERROR; + } + + ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size); + if (ash == NULL) { + WARN("no memory\n"); + return MMSYSERR_NOMEM; + } + + ash->cbStruct = sizeof(*ash); + ash->fdwStatus = 0L; + ash->dwUser = (DWORD)lpWaveHdrDst; + ash->pbSrc = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR); + ash->cbSrcLength = size; + /* ash->cbSrcLengthUsed */ + ash->dwSrcUser = 0L; /* FIXME ? */ + ash->pbDst = lpWaveHdrDst->lpData; + ash->cbDstLength = lpWaveHdrDst->dwBufferLength; + /* ash->cbDstLengthUsed */ + ash->dwDstUser = lpWaveHdrDst->dwUser; /* FIXME ? */ + dwRet = acmStreamPrepareHeader(wim->hAcmStream, ash, 0L); + if (dwRet != MMSYSERR_NOERROR) { + WARN("acmStreamPrepareHeader failed\n"); + goto errCleanUp; + } + + lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); + lpWaveHdrSrc->lpData = ash->pbSrc; + lpWaveHdrSrc->dwBufferLength = size; /* conversion is not done yet */ + lpWaveHdrSrc->dwFlags = 0; + lpWaveHdrSrc->dwLoops = 0; + dwRet = waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); + if (dwRet != MMSYSERR_NOERROR) { + WARN("waveInPrepareHeader failed\n"); + goto errCleanUp; + } + + lpWaveHdrDst->reserved = (DWORD)ash; + lpWaveHdrDst->dwFlags = WHDR_PREPARED; + TRACE("=> (0)\n"); + return MMSYSERR_NOERROR; +errCleanUp: + TRACE("=> (%ld)\n", dwRet); + HeapFree(GetProcessHeap(), 0, ash); + return dwRet; +} + +static DWORD widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) +{ + PACMSTREAMHEADER ash; + LPWAVEHDR lpWaveHdrSrc; + DWORD dwRet1, dwRet2; + + TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2); + + if (!wim->hAcmStream) { + return waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); + } + ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved; + dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L); + + lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); + dwRet2 = waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); + + HeapFree(GetProcessHeap(), 0, ash); + + lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED; + return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1; +} + +static DWORD widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2) +{ + DWORD val; + + TRACE("(%p %p %08lx)\n", wim, lpTime, dwParam2); + + val = waveInGetPosition(wim->u.in.hInnerWave, lpTime, dwParam2); + if (lpTime->wType == TIME_BYTES) + lpTime->u.cb = MulDiv(lpTime->u.cb, wim->avgSpeedOuter, wim->avgSpeedInner); + /* other time types don't require conversion */ + return val; +} + +static DWORD widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSA lpWaveCaps, DWORD dwParam2) +{ + TRACE("(%04x, %p %p %08lx)\n", wDevID, wim, lpWaveCaps, dwParam2); + + /* if opened low driver, forward message */ + if (WAVEMAP_IsData(wim)) + return waveInGetDevCapsA((UINT)wim->u.in.hInnerWave, lpWaveCaps, dwParam2); + /* else if no drivers, nothing to map so return bad device */ + if (waveInGetNumDevs() == 0) { + WARN("bad device id\n"); + return MMSYSERR_BADDEVICEID; + } + /* otherwise, return caps of mapper itself */ + if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) { + WAVEINCAPSA wic; + wic.wMid = 0x00FF; + wic.wPid = 0x0001; + wic.vDriverVersion = 0x0001; + strcpy(wic.szPname, "Wine wave in mapper"); + wic.dwFormats = + WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 | + WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | + WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 | + WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | + WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16; + wic.wChannels = 2; + memcpy(lpWaveCaps, &wic, min(dwParam2, sizeof(wic))); + + return MMSYSERR_NOERROR; + } + ERR("This shouldn't happen\n"); + return MMSYSERR_ERROR; +} + +static DWORD widStop(WAVEMAPDATA* wim) +{ + TRACE("(%p)\n", wim); + + return waveInStop(wim->u.in.hInnerWave); +} + +static DWORD widStart(WAVEMAPDATA* wim) +{ + TRACE("(%p)\n", wim); + + return waveInStart(wim->u.in.hInnerWave); +} + +static DWORD widReset(WAVEMAPDATA* wim) +{ + TRACE("(%p)\n", wim); + + return waveInReset(wim->u.in.hInnerWave); +} + +static DWORD widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr) +{ + UINT id; + DWORD ret = MMSYSERR_NOTSUPPORTED; + + TRACE("(%p %08lx %p)\n", wim, flags, ptr); + + switch (flags) { + case WAVEIN_MAPPER_STATUS_DEVICE: + ret = waveInGetID(wim->u.in.hInnerWave, &id); + *(LPDWORD)ptr = id; + break; + case WAVEIN_MAPPER_STATUS_MAPPED: + FIXME("Unsupported yet flag=%ld\n", flags); + *(LPDWORD)ptr = 0; /* FIXME ?? */ + break; + case WAVEIN_MAPPER_STATUS_FORMAT: + FIXME("Unsupported flag=%ld\n", flags); + /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */ + *(LPDWORD)ptr = 0; /* FIXME ?? */ + break; + default: + FIXME("Unsupported flag=%ld\n", flags); + *(LPDWORD)ptr = 0; + break; + } + return ret; +} + +/************************************************************************** + * widMessage (MSACM.@) + */ +DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, + DWORD dwParam1, DWORD dwParam2) +{ + TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n", + wDevID, wMsg, dwUser, dwParam1, dwParam2); + + switch (wMsg) { + case DRVM_INIT: + case DRVM_EXIT: + case DRVM_ENABLE: + case DRVM_DISABLE: + /* FIXME: Pretend this is supported */ + return 0; + + case WIDM_OPEN: return widOpen ((LPDWORD)dwUser, (LPWAVEOPENDESC)dwParam1, dwParam2); + case WIDM_CLOSE: return widClose ((WAVEMAPDATA*)dwUser); + + case WIDM_ADDBUFFER: return widAddBuffer ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); + case WIDM_PREPARE: return widPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); + case WIDM_UNPREPARE: return widUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); + case WIDM_GETDEVCAPS: return widGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSA)dwParam1, dwParam2); + case WIDM_GETNUMDEVS: return 1; + case WIDM_GETPOS: return widGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2); + case WIDM_RESET: return widReset ((WAVEMAPDATA*)dwUser); + case WIDM_START: return widStart ((WAVEMAPDATA*)dwUser); + case WIDM_STOP: return widStop ((WAVEMAPDATA*)dwUser); + case WIDM_MAPPER_STATUS: return widMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2); + /* known but not supported */ + case DRV_QUERYDEVICEINTERFACESIZE: + case DRV_QUERYDEVICEINTERFACE: + return MMSYSERR_NOTSUPPORTED; + default: + FIXME("unknown message %u!\n", wMsg); + } + return MMSYSERR_NOTSUPPORTED; +} + +/*======================================================================* + * Driver part * + *======================================================================*/ + +static struct WINE_WAVEMAP* oss = NULL; + +/************************************************************************** + * WAVEMAP_drvOpen [internal] + */ +static DWORD WAVEMAP_drvOpen(LPSTR str) +{ + TRACE("(%p)\n", str); + + if (oss) + return 0; + + /* I know, this is ugly, but who cares... */ + oss = (struct WINE_WAVEMAP*)1; + return 1; +} + +/************************************************************************** + * WAVEMAP_drvClose [internal] + */ +static DWORD WAVEMAP_drvClose(DWORD dwDevID) +{ + TRACE("(%08lx)\n", dwDevID); + + if (oss) { + oss = NULL; + return 1; + } + return 0; +} + +/************************************************************************** + * DriverProc (MSACM.@) + */ +LONG CALLBACK WAVEMAP_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, + DWORD dwParam1, DWORD dwParam2) +{ + TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n", + dwDevID, hDriv, wMsg, dwParam1, dwParam2); + + switch(wMsg) { + case DRV_LOAD: return 1; + case DRV_FREE: return 1; + case DRV_OPEN: return WAVEMAP_drvOpen((LPSTR)dwParam1); + case DRV_CLOSE: return WAVEMAP_drvClose(dwDevID); + case DRV_ENABLE: return 1; + case DRV_DISABLE: return 1; + case DRV_QUERYCONFIGURE: return 1; + case DRV_CONFIGURE: MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK); return 1; + case DRV_INSTALL: return DRVCNF_RESTART; + case DRV_REMOVE: return DRVCNF_RESTART; + default: + return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); + } +} diff --git a/reactos/lib/winmm/wavemap/wavemap.rc b/reactos/lib/winmm/wavemap/wavemap.rc new file mode 100644 index 00000000000..ab09929a1f8 --- /dev/null +++ b/reactos/lib/winmm/wavemap/wavemap.rc @@ -0,0 +1,7 @@ +/* $Id: wavemap.rc 11297 2004-10-16 20:27:43Z gvg $ */ + +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "ReactOS/WINE Wave Mapper\0" +#define REACTOS_STR_INTERNAL_NAME "wavemap\0" +#define REACTOS_STR_ORIGINAL_FILENAME "wavemap.drv\0" +#include diff --git a/reactos/lib/winmm/winemm.h b/reactos/lib/winmm/winemm.h new file mode 100644 index 00000000000..4ff8736e635 --- /dev/null +++ b/reactos/lib/winmm/winemm.h @@ -0,0 +1,310 @@ +/* -*- 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 + +#include "windef.h" +#include "winbase.h" +#include "mmddk.h" + +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 { + UINT16 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 function */ + 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 */ + DWORD 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 */ + UINT16 hTask; /* 2C handle to created task */ +} WINE_MMTHREAD; + +typedef struct tagWINE_MCIDRIVER { + UINT wDeviceID; + UINT wType; + LPSTR lpstrElementName; + LPSTR lpstrDeviceType; + LPSTR lpstrAlias; + HDRVR hDriver; + 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; + LPTIMECALLBACK lpFunc; /* can be lots of things */ + DWORD dwUser; + UINT16 wFlags; + UINT16 wTimerID; + DWORD dwTriggerTime; + 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; + DWORD segBuffer16; + DWORD dwFileSize; +} WINE_MMIO, *LPWINE_MMIO; + +typedef struct tagWINE_PLAYSOUND { + BOOL bLoop : 1, + bAlloc : 1; + LPCWSTR pszSound; + HMODULE hMod; + DWORD fdwSound; + HANDLE hThread; + struct tagWINE_PLAYSOUND* lpNext; +} WINE_PLAYSOUND, *LPWINE_PLAYSOUND; + +typedef struct tagWINE_MM_IDATA { + /* winmm part */ + HANDLE hWinMM32Instance; + HANDLE hWinMM16Instance; + CRITICAL_SECTION cs; + /* 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 (*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); + +HDRVR WINAPI OpenDriverA(LPCSTR lpDriverName, LPCSTR lpSectionName, LPARAM lParam2); +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, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR 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); + +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_PTR dwParam1, DWORD_PTR dwParam2); +DWORD MCI_SendCommandFrom16(UINT wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2); +UINT MCI_SetCommandTable(void *table, UINT uDevType); + +BOOL WINMM_CheckForMMSystem(void); +const char* WINMM_ErrorToString(MMRESULT error); + +UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD fdwOpen, BOOL bFrom32); +UINT MIDI_OutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32); +UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32); +MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, + DWORD cMidi, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD fdwOpen, BOOL bFrom32); +UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType, + const LPWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, + DWORD_PTR 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, LPTIMECALLBACK 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)(UINT16); +extern LPWINE_DRIVER (*pFnOpenDriver16)(LPCSTR,LPCSTR,LPARAM); +extern LRESULT (*pFnCloseDriver16)(UINT16,LPARAM,LPARAM); +extern LRESULT (*pFnSendMessage16)(UINT16,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)(DWORD /* in fact FARPROC16 */,WORD,WORD,LONG,LONG,LONG); +extern unsigned (*pFnLoadMMDrvFunc16)(LPCSTR,LPWINE_DRIVER, LPWINE_MM_DRIVER); +extern LRESULT (*pFnMmioCallback16)(DWORD,LPMMIOINFO,UINT,LPARAM,LPARAM); +extern void (WINAPI *pFnReleaseThunkLock)(DWORD*); +extern void (WINAPI *pFnRestoreThunkLock)(DWORD); +/* GetDriverFlags() returned bits is not documented (nor the call itself) + * Here are Wine only definitions of the bits + */ +#define WINE_GDF_EXIST 0x80000000 +#define WINE_GDF_16BIT 0x10000000 diff --git a/reactos/lib/winmm/winemm16.h b/reactos/lib/winmm/winemm16.h new file mode 100644 index 00000000000..9f0920e62ca --- /dev/null +++ b/reactos/lib/winmm/winemm16.h @@ -0,0 +1,59 @@ +/* -*- 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 "winemm.h" +#include "wine/mmsystem16.h" +#include "wownt32.h" + +/* 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); + +typedef LONG (*MCIPROC16)(DWORD, HDRVR16, WORD, DWORD, DWORD); + +/* 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..17c0e2e61cd --- /dev/null +++ b/reactos/lib/winmm/winmm.c @@ -0,0 +1,3332 @@ +/* -*- 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 + */ + +/* TODO + * + it seems that some programs check what's installed in + * registry against the value returned by drivers. Wine is + * currently broken regarding this point. + * + check thread-safeness for MMSYSTEM and WINMM entry points + * + unicode entry points are badly supported (would require + * moving 32 bit drivers as Unicode as they are supposed to be) + * + allow joystick and timer external calls as we do for wave, + * midi, mixer and aux + */ + +#include +#include +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "winuser.h" +#include "winnls.h" +#include "winreg.h" +#include "winternl.h" +#include "winemm.h" +#include "wownt32.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winmm); + +/****************************************************************** + * 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(); + } +} + +void (WINAPI *pFnReleaseThunkLock)(DWORD*); +void (WINAPI *pFnRestoreThunkLock)(DWORD); + +/* ======================================================================== + * 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); +/* FIXME crashes in ReactOS + WINMM_IData->cs.DebugInfo->Spare[1] = (DWORD)"WINMM_IData"; +*/ + 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) + { +#ifndef __REACTOS__ + pGetModuleHandle16 = (void*)GetProcAddress(h, "GetModuleHandle16"); + pLoadLibrary16 = (void*)GetProcAddress(h, "LoadLibrary16"); + if (pGetModuleHandle16 && pLoadLibrary16 && + (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL"))) +#endif /* __REACTOS__ */ + loaded = 1; + } + } + return loaded > 0; +} + +/****************************************************************** + * WINMM_ErrorToString + */ +const char* WINMM_ErrorToString(MMRESULT error) +{ +#define ERR_TO_STR(dev) case dev: return #dev + static char unknown[32]; + switch (error) { + ERR_TO_STR(MMSYSERR_NOERROR); + ERR_TO_STR(MMSYSERR_ERROR); + ERR_TO_STR(MMSYSERR_BADDEVICEID); + ERR_TO_STR(MMSYSERR_NOTENABLED); + ERR_TO_STR(MMSYSERR_ALLOCATED); + ERR_TO_STR(MMSYSERR_INVALHANDLE); + ERR_TO_STR(MMSYSERR_NODRIVER); + ERR_TO_STR(MMSYSERR_NOMEM); + ERR_TO_STR(MMSYSERR_NOTSUPPORTED); + ERR_TO_STR(MMSYSERR_BADERRNUM); + ERR_TO_STR(MMSYSERR_INVALFLAG); + ERR_TO_STR(MMSYSERR_INVALPARAM); + ERR_TO_STR(MMSYSERR_HANDLEBUSY); + ERR_TO_STR(MMSYSERR_INVALIDALIAS); + ERR_TO_STR(MMSYSERR_BADDB); + ERR_TO_STR(MMSYSERR_KEYNOTFOUND); + ERR_TO_STR(MMSYSERR_READERROR); + ERR_TO_STR(MMSYSERR_WRITEERROR); + ERR_TO_STR(MMSYSERR_DELETEERROR); + ERR_TO_STR(MMSYSERR_VALNOTFOUND); + ERR_TO_STR(MMSYSERR_NODRIVERCB); + ERR_TO_STR(WAVERR_BADFORMAT); + ERR_TO_STR(WAVERR_STILLPLAYING); + ERR_TO_STR(WAVERR_UNPREPARED); + ERR_TO_STR(WAVERR_SYNC); + } + sprintf(unknown, "Unknown(0x%08x)", error); + return unknown; +#undef ERR_TO_STR +} + +/************************************************************************** + * 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 (!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 UINT MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags, LPWINE_MIXER * lplpwm) +{ + LPWINE_MIXER lpwm = NULL; + UINT uRet = MMSYSERR_NOERROR; + + 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: + WARN("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul); + lpwm = 0; + uRet = MMSYSERR_INVALFLAG; + break; + } + *lplpwm = lpwm; + if (lpwm == 0 && uRet == MMSYSERR_NOERROR) + uRet = MMSYSERR_INVALPARAM; + return uRet; +} + +/************************************************************************** + * mixerGetNumDevs [WINMM.@] + */ +UINT WINAPI mixerGetNumDevs(void) +{ + return MMDRV_GetNum(MMDRV_MIXER); +} + +/************************************************************************** + * mixerGetDevCapsA [WINMM.@] + */ +UINT WINAPI mixerGetDevCapsA(UINT_PTR uDeviceID, LPMIXERCAPSA lpCaps, UINT uSize) +{ + LPWINE_MLD wmld; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIXER, TRUE)) == NULL) + return MMSYSERR_BADDEVICEID; + + return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE); +} + +/************************************************************************** + * mixerGetDevCapsW [WINMM.@] + */ +UINT WINAPI mixerGetDevCapsW(UINT_PTR uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize) +{ + MIXERCAPSA micA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = mixerGetDevCapsA(uDeviceID, &micA, sizeof(micA)); + if (ret == MMSYSERR_NOERROR) { + MIXERCAPSW micW; + micW.wMid = micA.wMid; + micW.wPid = micA.wPid; + micW.vDriverVersion = micA.vDriverVersion; + MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, micW.szPname, + sizeof(micW.szPname)/sizeof(WCHAR) ); + micW.fdwSupport = micA.fdwSupport; + micW.cDestinations = micA.cDestinations; + memcpy(lpCaps, &micW, min(uSize, sizeof(micW))); + } + return ret; +} + +UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback, + DWORD_PTR 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_PTR dwCallback, + DWORD_PTR 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; + UINT uRet = MMSYSERR_NOERROR; + + TRACE("(%p %p %08lx)\n", hmix, lpid, fdwID); + + if ((uRet = MIXER_GetDev(hmix, fdwID, &lpwm)) != MMSYSERR_NOERROR) + return uRet; + + if (lpid) + *lpid = lpwm->mld.uDeviceID; + + return uRet; +} + +/************************************************************************** + * mixerGetControlDetailsA [WINMM.@] + */ +UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA, + DWORD fdwDetails) +{ + LPWINE_MIXER lpwm; + UINT uRet = MMSYSERR_NOERROR; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails); + + if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR) + return uRet; + + if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA)) + return MMSYSERR_INVALPARAM; + + return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD_PTR)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); + unsigned int i; + + if (lpmcd->u.cMultipleItems != 0) { + size *= lpmcd->u.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;iu.cMultipleItems*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->u.cMultipleItems*lpmcd->cChannels; + pDetailsW -= lpmcd->u.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; + UINT uRet = MMSYSERR_NOERROR; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmlcA, fdwControls); + + if ((uRet = MIXER_GetDev(hmix, fdwControls, &lpwm)) != MMSYSERR_NOERROR) + return uRet; + + if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA)) + return MMSYSERR_INVALPARAM; + + return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD_PTR)lpmlcA, + fdwControls, TRUE); +} + +/************************************************************************** + * mixerGetLineControlsW [WINMM.@] + */ +UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW, + DWORD fdwControls) +{ + MIXERLINECONTROLSA mlcA; + DWORD ret; + unsigned 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.u.dwControlID = lpmlcW->u.dwControlID; + mlcA.u.dwControlType = lpmlcW->u.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->u.dwControlID = mlcA.u.dwControlID; + lpmlcW->u.dwControlType = mlcA.u.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; + UINT uRet = MMSYSERR_NOERROR; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo); + + if ((uRet = MIXER_GetDev(hmix, fdwInfo, &lpwm)) != MMSYSERR_NOERROR) + return uRet; + + return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD_PTR)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: + WARN("Unsupported fdwControls=0x%08lx\n", fdwInfo); + return MMSYSERR_INVALFLAG; + } + + 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; + UINT uRet = MMSYSERR_NOERROR; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails); + + if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR) + return uRet; + + return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD_PTR)lpmcdA, + fdwDetails, TRUE); +} + +/************************************************************************** + * mixerMessage [WINMM.@] + */ +DWORD WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR 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_PTR uDeviceID, LPAUXCAPSW lpCaps, UINT uSize) +{ + AUXCAPSA acA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA)); + if (ret == MMSYSERR_NOERROR) { + AUXCAPSW acW; + acW.wMid = acA.wMid; + acW.wPid = acA.wPid; + acW.vDriverVersion = acA.vDriverVersion; + MultiByteToWideChar( CP_ACP, 0, acA.szPname, -1, acW.szPname, + sizeof(acW.szPname)/sizeof(WCHAR) ); + acW.wTechnology = acA.wTechnology; + acW.dwSupport = acA.dwSupport; + memcpy(lpCaps, &acW, min(uSize, sizeof(acW))); + } + return ret; +} + +/************************************************************************** + * auxGetDevCapsA [WINMM.@] + */ +UINT WINAPI auxGetDevCapsA(UINT_PTR uDeviceID, LPAUXCAPSA lpCaps, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize); + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD_PTR)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_PTR)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.@] + */ +UINT WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD_PTR dw1, DWORD_PTR 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(MCIERROR wError, LPWSTR lpstrBuffer, UINT uLength) +{ + char bufstr[MAXERRORLENGTH]; + BOOL ret = mciGetErrorStringA(wError, bufstr, MAXERRORLENGTH); + + MultiByteToWideChar( CP_ACP, 0, bufstr, -1, lpstrBuffer, uLength ); + return ret; +} + +/************************************************************************** + * mciGetErrorStringA [WINMM.@] + */ +BOOL WINAPI mciGetErrorStringA(MCIERROR dwError, LPSTR lpstrBuffer, UINT uLength) +{ + BOOL 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, MCIDEVICEID wDevID, UINT wStatus) +{ + TRACE("(%p, %04x, %04X)\n", hWndCallBack, wDevID, wStatus); + + return PostMessageW(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID); +} + +/************************************************************************** + * mciGetDriverData [WINMM.@] + */ +DWORD WINAPI mciGetDriverData(MCIDEVICEID 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(MCIDEVICEID 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(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR 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; +} + +inline static LPSTR strdupWtoA( LPCWSTR str ) +{ + LPSTR ret; + INT len; + + if (!str) return NULL; + len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); + ret = HeapAlloc( GetProcessHeap(), 0, len ); + if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL ); + return ret; +} + +static int MCI_MapMsgWtoA(UINT msg, DWORD_PTR dwParam1, DWORD_PTR *dwParam2) +{ + switch(msg) + { + case MCI_CLOSE: + case MCI_PLAY: + case MCI_SEEK: + case MCI_STOP: + case MCI_PAUSE: + case MCI_GETDEVCAPS: + case MCI_SPIN: + case MCI_SET: + case MCI_STEP: + case MCI_RECORD: + case MCI_BREAK: + case MCI_SOUND: + case MCI_STATUS: + case MCI_CUE: + case MCI_REALIZE: + case MCI_PUT: + case MCI_WHERE: + case MCI_FREEZE: + case MCI_UNFREEZE: + case MCI_CUT: + case MCI_COPY: + case MCI_PASTE: + case MCI_UPDATE: + case MCI_RESUME: + case MCI_DELETE: + return 0; + + case MCI_OPEN: + { + MCI_OPEN_PARMSW *mci_openW = (MCI_OPEN_PARMSW *)*dwParam2; + MCI_OPEN_PARMSA *mci_openA; + DWORD_PTR *ptr; + + ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_openA) + sizeof(DWORD_PTR)); + if (!ptr) return -1; + + *ptr++ = *dwParam2; /* save the previous pointer */ + *dwParam2 = (DWORD_PTR)ptr; + mci_openA = (MCI_OPEN_PARMSA *)ptr; + + if (dwParam1 & MCI_NOTIFY) + mci_openA->dwCallback = mci_openW->dwCallback; + + if (dwParam1 & MCI_OPEN_TYPE) + { + if (dwParam1 & MCI_OPEN_TYPE_ID) + mci_openA->lpstrDeviceType = (LPSTR)mci_openW->lpstrDeviceType; + else + mci_openA->lpstrDeviceType = strdupWtoA(mci_openW->lpstrDeviceType); + } + if (dwParam1 & MCI_OPEN_ELEMENT) + { + if (dwParam1 & MCI_OPEN_ELEMENT_ID) + mci_openA->lpstrElementName = (LPSTR)mci_openW->lpstrElementName; + else + mci_openA->lpstrElementName = strdupWtoA(mci_openW->lpstrElementName); + } + if (dwParam1 & MCI_OPEN_ALIAS) + mci_openA->lpstrAlias = strdupWtoA(mci_openW->lpstrAlias); + } + return 1; + + case MCI_WINDOW: + if (dwParam1 & MCI_ANIM_WINDOW_TEXT) + { + MCI_ANIM_WINDOW_PARMSW *mci_windowW = (MCI_ANIM_WINDOW_PARMSW *)*dwParam2; + MCI_ANIM_WINDOW_PARMSA *mci_windowA; + + mci_windowA = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_windowA)); + if (!mci_windowA) return -1; + + *dwParam2 = (DWORD_PTR)mci_windowA; + + mci_windowA->lpstrText = strdupWtoA(mci_windowW->lpstrText); + + if (dwParam1 & MCI_NOTIFY) + mci_windowA->dwCallback = mci_windowW->dwCallback; + if (dwParam1 & MCI_ANIM_WINDOW_HWND) + mci_windowA->hWnd = mci_windowW->hWnd; + if (dwParam1 & MCI_ANIM_WINDOW_STATE) + mci_windowA->nCmdShow = mci_windowW->nCmdShow; + + return 1; + } + return 0; + + case MCI_SYSINFO: + { + MCI_SYSINFO_PARMSW *mci_sysinfoW = (MCI_SYSINFO_PARMSW *)*dwParam2; + MCI_SYSINFO_PARMSA *mci_sysinfoA; + DWORD_PTR *ptr; + + ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_sysinfoA) + sizeof(DWORD_PTR)); + if (!ptr) return -1; + + *ptr++ = *dwParam2; /* save the previous pointer */ + *dwParam2 = (DWORD_PTR)ptr; + mci_sysinfoA = (MCI_SYSINFO_PARMSA *)ptr; + + if (dwParam1 & MCI_NOTIFY) + mci_sysinfoA->dwCallback = mci_sysinfoW->dwCallback; + + mci_sysinfoA->dwRetSize = mci_sysinfoW->dwRetSize; /* FIXME */ + mci_sysinfoA->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mci_sysinfoA->dwRetSize); + + return 1; + } + + case MCI_INFO: + case MCI_SAVE: + case MCI_LOAD: + case MCI_ESCAPE: + default: + FIXME("Message 0x%04x needs translation\n", msg); + return -1; + } + return 0; +} + +static DWORD MCI_UnmapMsgWtoA(UINT msg, DWORD_PTR dwParam1, DWORD_PTR dwParam2, + DWORD result) +{ + switch(msg) + { + case MCI_OPEN: + { + DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1; + MCI_OPEN_PARMSW *mci_openW = (MCI_OPEN_PARMSW *)*ptr; + MCI_OPEN_PARMSA *mci_openA = (MCI_OPEN_PARMSA *)(ptr + 1); + + mci_openW->wDeviceID = mci_openA->wDeviceID; + + if (dwParam1 & MCI_OPEN_TYPE) + { + if (!(dwParam1 & MCI_OPEN_TYPE_ID)) + HeapFree(GetProcessHeap(), 0, mci_openA->lpstrDeviceType); + } + if (dwParam1 & MCI_OPEN_ELEMENT) + { + if (!(dwParam1 & MCI_OPEN_ELEMENT_ID)) + HeapFree(GetProcessHeap(), 0, mci_openA->lpstrElementName); + } + if (dwParam1 & MCI_OPEN_ALIAS) + HeapFree(GetProcessHeap(), 0, mci_openA->lpstrAlias); + HeapFree(GetProcessHeap(), 0, ptr); + } + break; + + case MCI_WINDOW: + if (dwParam1 & MCI_ANIM_WINDOW_TEXT) + { + MCI_ANIM_WINDOW_PARMSA *mci_windowA = (MCI_ANIM_WINDOW_PARMSA *)dwParam2; + + HeapFree(GetProcessHeap(), 0, (void *)mci_windowA->lpstrText); + HeapFree(GetProcessHeap(), 0, mci_windowA); + } + break; + + case MCI_SYSINFO: + { + DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1; + MCI_SYSINFO_PARMSW *mci_sysinfoW = (MCI_SYSINFO_PARMSW *)*ptr; + MCI_SYSINFO_PARMSA *mci_sysinfoA = (MCI_SYSINFO_PARMSA *)(ptr + 1); + + if (!result) + { + mci_sysinfoW->dwNumber = mci_sysinfoA->dwNumber; + mci_sysinfoW->wDeviceType = mci_sysinfoA->wDeviceType; + MultiByteToWideChar(CP_ACP, 0, + mci_sysinfoA->lpstrReturn, mci_sysinfoA->dwRetSize, + mci_sysinfoW->lpstrReturn, mci_sysinfoW->dwRetSize); + } + + HeapFree(GetProcessHeap(), 0, mci_sysinfoA->lpstrReturn); + HeapFree(GetProcessHeap(), 0, ptr); + } + break; + + default: + FIXME("Message 0x%04x needs unmapping\n", msg); + break; + } + + return result; +} + + +/************************************************************************** + * mciSendCommandW [WINMM.@] + * + * FIXME: we should do the things other way around, but since our + * MM subsystem is not unicode aware... + */ +DWORD WINAPI mciSendCommandW(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + DWORD ret; + int mapped; + + TRACE("(%08x, %s, %08lx, %08lx)\n", + wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2); + + mapped = MCI_MapMsgWtoA(wMsg, dwParam1, &dwParam2); + if (mapped == -1) + { + FIXME("message %04x mapping failed\n", wMsg); + return MMSYSERR_NOMEM; + } + ret = mciSendCommandA(wDevID, wMsg, dwParam1, dwParam2); + if (mapped) + MCI_UnmapMsgWtoA(wMsg, dwParam1, dwParam2, ret); + return ret; +} + +/************************************************************************** + * mciGetDeviceIDA [WINMM.@] + */ +UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName) +{ + return MCI_GetDriverFromString(lpstrName); +} + +/************************************************************************** + * mciGetDeviceIDW [WINMM.@] + */ +UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName) +{ + LPSTR lpstrName = NULL; + UINT ret; + INT len; + + if (lpwstrName) { + len = WideCharToMultiByte( CP_ACP, 0, lpwstrName, -1, NULL, 0, NULL, NULL ); + lpstrName = HeapAlloc( GetProcessHeap(), 0, len ); + if (lpstrName) WideCharToMultiByte( CP_ACP, 0, lpwstrName, -1, lpstrName, len, NULL, NULL ); + } + 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_32(HIWORD(data)); + while (!PeekMessageA(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); + ret = -1; + } + return ret; +} + +/************************************************************************** + * mciSetYieldProc [WINMM.@] + */ +BOOL WINAPI mciSetYieldProc(MCIDEVICEID 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(MCIDEVICEID 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(MCIDEVICEID 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(MCIDEVICEID 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_PTR uDeviceID, LPMIDIOUTCAPSW lpCaps, + UINT uSize) +{ + MIDIOUTCAPSA mocA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA)); + if (ret == MMSYSERR_NOERROR) { + MIDIOUTCAPSW mocW; + mocW.wMid = mocA.wMid; + mocW.wPid = mocA.wPid; + mocW.vDriverVersion = mocA.vDriverVersion; + MultiByteToWideChar( CP_ACP, 0, mocA.szPname, -1, mocW.szPname, + sizeof(mocW.szPname)/sizeof(WCHAR) ); + mocW.wTechnology = mocA.wTechnology; + mocW.wVoices = mocA.wVoices; + mocW.wNotes = mocA.wNotes; + mocW.wChannelMask = mocA.wChannelMask; + mocW.dwSupport = mocA.dwSupport; + memcpy(lpCaps, &mocW, min(uSize, sizeof(mocW))); + } + return ret; +} + +/************************************************************************** + * midiOutGetDevCapsA [WINMM.@] + */ +UINT WINAPI midiOutGetDevCapsA(UINT_PTR 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_PTR)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(LPHMIDIOUT lphMidiOut, UINT uDeviceID, DWORD_PTR dwCallback, + DWORD_PTR 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(LPHMIDIOUT lphMidiOut, UINT uDeviceID, + DWORD_PTR dwCallback, DWORD_PTR 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 (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR)) + return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_PREPARE, (DWORD_PTR)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 == NULL || uSize < sizeof (MIDIHDR)) + return MMSYSERR_INVALPARAM; + + 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_PTR)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_PTR)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_PTR)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.@] + */ +UINT WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage, + DWORD_PTR dwParam1, DWORD_PTR 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_PTR uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize) +{ + MIDIINCAPSA micA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = midiInGetDevCapsA(uDeviceID, &micA, sizeof(micA)); + if (ret == MMSYSERR_NOERROR) { + MIDIINCAPSW micW; + micW.wMid = micA.wMid; + micW.wPid = micA.wPid; + micW.vDriverVersion = micA.vDriverVersion; + MultiByteToWideChar( CP_ACP, 0, micA.szPname, -1, micW.szPname, + sizeof(micW.szPname)/sizeof(WCHAR) ); + micW.dwSupport = micA.dwSupport; + memcpy(lpCaps, &micW, min(uSize, sizeof(micW))); + } + return ret; +} + +/************************************************************************** + * midiInGetDevCapsA [WINMM.@] + */ +UINT WINAPI midiInGetDevCapsA(UINT_PTR uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize); + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD_PTR)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_PTR dwCallback, + DWORD_PTR 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_PTR dwCallback, DWORD_PTR 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 (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR)) + return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD_PTR)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 == NULL || uSize < sizeof (MIDIHDR)) + return MMSYSERR_INVALPARAM; + + 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_PTR)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_PTR)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.@] + */ +UINT WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage, + DWORD_PTR dwParam1, DWORD_PTR 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; + + if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count); + WaitForSingleObject(lpMidiStrm->hEvent, INFINITE); + if (pFnRestoreThunkLock) pFnRestoreThunkLock(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_PTR dwCallback, DWORD_PTR 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; + + lpwm->mld.uDeviceID = *lpuDeviceID; + + 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. + */ + if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count); + WaitForSingleObject(lpMidiStrm->hEvent, INFINITE); + if (pFnRestoreThunkLock) pFnRestoreThunkLock(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_PTR dwCallback, + DWORD_PTR 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, + const LPWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, + DWORD_PTR 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) { + WARN("bad format\n"); + return WAVERR_BADFORMAT; + } + + if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1)) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } + + /* may have a PCMWAVEFORMAT rather than a WAVEFORMATEX so don't read cbSize */ + TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u\n", + lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec, + lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample); + + if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle, + &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL) { + WARN("no memory\n"); + 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); + + TRACE("dwRet = %s\n", WINMM_ErrorToString(dwRet)); + if (dwRet != WAVERR_BADFORMAT || + ((dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) || (uDeviceID == WAVE_MAPPER)) 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 or the device is already the mapper) + */ + 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("=> %s hWave=%p\n", WINMM_ErrorToString(dwRet), handle); + + return dwRet; +} + +/************************************************************************** + * waveOutGetNumDevs [WINMM.@] + */ +UINT WINAPI waveOutGetNumDevs(void) +{ + return MMDRV_GetNum(MMDRV_WAVEOUT); +} + +/************************************************************************** + * waveOutGetDevCapsA [WINMM.@] + */ +UINT WINAPI waveOutGetDevCapsA(UINT_PTR 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_PTR)lpCaps, uSize, TRUE); + +} + +/************************************************************************** + * waveOutGetDevCapsW [WINMM.@] + */ +UINT WINAPI waveOutGetDevCapsW(UINT_PTR 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) { + WAVEOUTCAPSW wocW; + wocW.wMid = wocA.wMid; + wocW.wPid = wocA.wPid; + wocW.vDriverVersion = wocA.vDriverVersion; + MultiByteToWideChar( CP_ACP, 0, wocA.szPname, -1, wocW.szPname, + sizeof(wocW.szPname)/sizeof(WCHAR) ); + wocW.dwFormats = wocA.dwFormats; + wocW.wChannels = wocA.wChannels; + wocW.dwSupport = wocA.dwSupport; + memcpy(lpCaps, &wocW, min(uSize, sizeof(wocW))); + } + 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(LPHWAVEOUT lphWaveOut, UINT uDeviceID, + LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, + DWORD_PTR 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); + if (dwRet != WAVERR_STILLPLAYING) + MMDRV_Free(hWaveOut, wmld); + + return dwRet; +} + +/************************************************************************** + * waveOutPrepareHeader [WINMM.@] + */ +UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut, + WAVEHDR* lpWaveOutHdr, UINT uSize) +{ + LPWINE_MLD wmld; + UINT result; + + TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); + + if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR)) + return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + if ((result = MMDRV_Message(wmld, WODM_PREPARE, (DWORD_PTR)lpWaveOutHdr, + uSize, TRUE)) != MMSYSERR_NOTSUPPORTED) + return result; + + if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE) + return WAVERR_STILLPLAYING; + + lpWaveOutHdr->dwFlags |= WHDR_PREPARED; + lpWaveOutHdr->dwFlags &= ~WHDR_DONE; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * waveOutUnprepareHeader [WINMM.@] + */ +UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut, + LPWAVEHDR lpWaveOutHdr, UINT uSize) +{ + LPWINE_MLD wmld; + UINT result; + + TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); + + if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR)) + return MMSYSERR_INVALPARAM; + + if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + if ((result = MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD_PTR)lpWaveOutHdr, + uSize, TRUE)) != MMSYSERR_NOTSUPPORTED) + return result; + + if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE) + return WAVERR_STILLPLAYING; + + lpWaveOutHdr->dwFlags &= ~WHDR_PREPARED; + lpWaveOutHdr->dwFlags |= WHDR_DONE; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * 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_PTR)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_PTR)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_PTR)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_PTR)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_PTR)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.@] + */ +UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage, + DWORD_PTR dwParam1, DWORD_PTR 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); + } + WARN("invalid handle\n"); + return MMSYSERR_INVALHANDLE; + } + + /* from M$ KB */ + if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) { + WARN("invalid parameter\n"); + 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_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize) +{ + WAVEINCAPSA wicA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA)); + if (ret == MMSYSERR_NOERROR) { + WAVEINCAPSW wicW; + wicW.wMid = wicA.wMid; + wicW.wPid = wicA.wPid; + wicW.vDriverVersion = wicA.vDriverVersion; + MultiByteToWideChar( CP_ACP, 0, wicA.szPname, -1, wicW.szPname, + sizeof(wicW.szPname)/sizeof(WCHAR) ); + wicW.dwFormats = wicA.dwFormats; + wicW.wChannels = wicA.wChannels; + memcpy(lpCaps, &wicW, min(uSize, sizeof(wicW))); + } + return ret; +} + +/************************************************************************** + * waveInGetDevCapsA [WINMM.@] + */ +UINT WINAPI waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA 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_WAVEIN, TRUE)) == NULL) + return MMSYSERR_BADDEVICEID; + + return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD_PTR)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_PTR dwCallback, + DWORD_PTR 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); + if (dwRet != WAVERR_STILLPLAYING) + 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 || uSize < sizeof (WAVEHDR)) + 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_PTR)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 || uSize < sizeof (WAVEHDR)) + 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_PTR)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_PTR)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_PTR)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.@] + */ +UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage, + DWORD_PTR dwParam1, DWORD_PTR 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); +} + +struct mm_starter +{ + LPTASKCALLBACK cb; + DWORD client; + HANDLE event; +}; + +static DWORD WINAPI mmTaskRun(void* pmt) +{ + struct mm_starter mms; + + memcpy(&mms, pmt, sizeof(struct mm_starter)); + HeapFree(GetProcessHeap(), 0, pmt); + mms.cb(mms.client); + if (mms.event) SetEvent(mms.event); + return 0; +} + +/****************************************************************** + * mmTaskCreate (WINMM.@) + */ +MMRESULT WINAPI mmTaskCreate(LPTASKCALLBACK cb, HANDLE* ph, DWORD client) +{ + HANDLE hThread; + HANDLE hEvent = 0; + struct mm_starter *mms; + + mms = HeapAlloc(GetProcessHeap(), 0, sizeof(struct mm_starter)); + if (mms == NULL) return TASKERR_OUTOFMEMORY; + + mms->cb = cb; + mms->client = client; + if (ph) hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + mms->event = hEvent; + + hThread = CreateThread(0, 0, mmTaskRun, mms, 0, NULL); + if (!hThread) { + HeapFree(GetProcessHeap(), 0, mms); + if (hEvent) CloseHandle(hEvent); + return TASKERR_OUTOFMEMORY; + } + if (ph) *ph = hEvent; + CloseHandle(hThread); + return 0; +} + +/****************************************************************** + * mmTaskBlock (WINMM.@) + */ +void WINAPI mmTaskBlock(HANDLE tid) +{ + MSG msg; + + do + { + GetMessageA(&msg, 0, 0, 0); + if (msg.hwnd) DispatchMessageA(&msg); + } while (msg.message != WM_USER); +} + +/****************************************************************** + * mmTaskSignal (WINMM.@) + */ +BOOL WINAPI mmTaskSignal(HANDLE tid) +{ + return PostThreadMessageW((DWORD)tid, WM_USER, 0, 0); +} + +/****************************************************************** + * mmTaskYield (WINMM.@) + */ +void WINAPI mmTaskYield(void) {} + +/****************************************************************** + * mmGetCurrentTask (WINMM.@) + */ +HANDLE WINAPI mmGetCurrentTask(void) +{ + return (HANDLE)GetCurrentThreadId(); +} diff --git a/reactos/lib/winmm/winmm.spec b/reactos/lib/winmm/winmm.spec new file mode 100644 index 00000000000..b7057f46329 --- /dev/null +++ b/reactos/lib/winmm/winmm.spec @@ -0,0 +1,192 @@ +# ordinal exports +1 stdcall @(ptr long long) PlaySoundA +3 stub @ +4 stub @ + +@ stdcall PlaySoundA(ptr long long) +@ stdcall CloseDriver(long long long) +@ stdcall DefDriverProc(long long long long long) +@ stdcall DriverCallback(long long long long long long long) +@ stdcall DrvClose(long long long) CloseDriver +@ stdcall DrvDefDriverProc(long long long long long) DefDriverProc +@ stdcall DrvGetModuleHandle(long) GetDriverModuleHandle +@ stdcall DrvOpen(wstr wstr long) OpenDriverW +@ stdcall DrvOpenA(str str long) OpenDriverA +@ stdcall DrvSendMessage(long long long long) SendDriverMessage +@ stdcall GetDriverFlags(long) +@ stdcall GetDriverModuleHandle(long) +@ stdcall OpenDriver(wstr wstr long) OpenDriverW +@ stdcall OpenDriverA(str str long) +@ stdcall PlaySound(ptr long long) PlaySoundA +@ stdcall PlaySoundW(ptr long long) +@ stdcall SendDriverMessage(long long long long) +@ stdcall auxGetDevCapsA(long ptr long) +@ stdcall auxGetDevCapsW(long ptr long) +@ stdcall auxGetNumDevs() +@ stdcall auxGetVolume(long ptr) +@ stdcall auxOutMessage(long long long long) +@ stdcall auxSetVolume(long long) +@ stub joyConfigChanged +@ stdcall joyGetDevCapsA(long ptr long) +@ stdcall joyGetDevCapsW(long ptr long) +@ stdcall joyGetNumDevs() +@ stdcall joyGetPos(long ptr) +@ stdcall joyGetPosEx(long ptr) +@ stdcall joyGetThreshold(long ptr) +@ stdcall joyReleaseCapture(long) +@ stdcall joySetCapture(long long long long) +@ stdcall joySetThreshold(long long) +@ stdcall mciDriverNotify(long long long) +@ stdcall mciDriverYield(long) +@ stdcall mciExecute(str) +@ stdcall mciFreeCommandResource(long) +@ stdcall mciGetCreatorTask(long) +@ stdcall mciGetDeviceIDA(str) +@ stdcall mciGetDeviceIDFromElementIDW(long str) +@ stdcall mciGetDeviceIDW(str) +@ stdcall mciGetDriverData(long) +@ stdcall mciGetErrorStringA(long ptr long) +@ stdcall mciGetErrorStringW(long ptr long) +@ stdcall mciGetYieldProc(long ptr) +@ stdcall mciLoadCommandResource(long wstr long) +@ stdcall mciSendCommandA(long long long long) +@ stdcall mciSendCommandW(long long long long) +@ stdcall mciSendStringA(str ptr long long) +@ stdcall mciSendStringW(wstr ptr long long) +@ stdcall mciSetDriverData(long long) +@ stdcall mciSetYieldProc(long ptr long) +@ stub midiConnect +@ stub midiDisconnect +@ stdcall midiInAddBuffer(long ptr long) +@ stdcall midiInClose(long) +@ stdcall midiInGetDevCapsA(long ptr long) +@ stdcall midiInGetDevCapsW(long ptr long) +@ stdcall midiInGetErrorTextA(long ptr long) +@ stdcall midiInGetErrorTextW(long ptr long) +@ stdcall midiInGetID(long ptr) +@ stdcall midiInGetNumDevs() +@ stdcall midiInMessage(long long long long) +@ stdcall midiInOpen(ptr long long long long) +@ stdcall midiInPrepareHeader(long ptr long) +@ stdcall midiInReset(long) +@ stdcall midiInStart(long) +@ stdcall midiInStop(long) +@ stdcall midiInUnprepareHeader(long ptr long) +@ stdcall midiOutCacheDrumPatches(long long ptr long) +@ stdcall midiOutCachePatches(long long ptr long) +@ stdcall midiOutClose(long) +@ stdcall midiOutGetDevCapsA(long ptr long) +@ stdcall midiOutGetDevCapsW(long ptr long) +@ stdcall midiOutGetErrorTextA(long ptr long) +@ stdcall midiOutGetErrorTextW(long ptr long) +@ stdcall midiOutGetID(long ptr) +@ stdcall midiOutGetNumDevs() +@ stdcall midiOutGetVolume(long ptr) +@ stdcall midiOutLongMsg(long ptr long) +@ stdcall midiOutMessage(long long long long) +@ stdcall midiOutOpen(ptr long long long long) +@ stdcall midiOutPrepareHeader(long ptr long) +@ stdcall midiOutReset(long) +@ stdcall midiOutSetVolume(long ptr) +@ stdcall midiOutShortMsg(long long) +@ stdcall midiOutUnprepareHeader(long ptr long) +@ stdcall midiStreamClose(long) +@ stdcall midiStreamOpen(ptr ptr long long long long) +@ stdcall midiStreamOut(long ptr long) +@ stdcall midiStreamPause(long) +@ stdcall midiStreamPosition(long ptr long) +@ stdcall midiStreamProperty(long ptr long) +@ stdcall midiStreamRestart(long) +@ stdcall midiStreamStop(long) +@ stdcall mixerClose(long) +@ stdcall mixerGetControlDetailsA(long ptr long) +@ stdcall mixerGetControlDetailsW(long ptr long) +@ stdcall mixerGetDevCapsA(long ptr long) +@ stdcall mixerGetDevCapsW(long ptr long) +@ stdcall mixerGetID(long ptr long) +@ stdcall mixerGetLineControlsA(long ptr long) +@ stdcall mixerGetLineControlsW(long ptr long) +@ stdcall mixerGetLineInfoA(long ptr long) +@ stdcall mixerGetLineInfoW(long ptr long) +@ stdcall mixerGetNumDevs() +@ stdcall mixerMessage(long long long long) +@ stdcall mixerOpen(ptr long long long long) +@ stdcall mixerSetControlDetails(long ptr long) +@ stdcall mmGetCurrentTask() +@ stdcall mmioAdvance(long ptr long) +@ stdcall mmioAscend(long ptr long) +@ stdcall mmioClose(long long) +@ stdcall mmioCreateChunk(long ptr long) +@ stdcall mmioDescend(long ptr ptr long) +@ stdcall mmioFlush(long long) +@ stdcall mmioGetInfo(long ptr long) +@ stub mmioInstallIOProc16 +@ stdcall mmioInstallIOProcA(long ptr long) +@ stdcall mmioInstallIOProcW(long ptr long) +@ stdcall mmioOpenA(str ptr long) +@ stdcall mmioOpenW(wstr ptr long) +@ stdcall mmioRead(long ptr long) +@ stdcall mmioRenameA(str str ptr long) +@ stdcall mmioRenameW(wstr wstr ptr long) +@ stdcall mmioSeek(long long long) +@ stdcall mmioSendMessage(long long long long) +@ stdcall mmioSetBuffer(long ptr long long) +@ stdcall mmioSetInfo(long ptr long) +@ stdcall mmioStringToFOURCCA(str long) +@ stdcall mmioStringToFOURCCW(wstr long) +@ stdcall mmioWrite(long ptr long) +@ stdcall mmsystemGetVersion() +@ stdcall mmTaskBlock(long) +@ stdcall mmTaskCreate(ptr ptr long) +@ stdcall mmTaskSignal(long) +@ stdcall mmTaskYield() +@ stdcall sndPlaySoundA(ptr long) +@ stdcall sndPlaySoundW(ptr long) +@ stdcall timeBeginPeriod(long) +@ stdcall timeEndPeriod(long) +@ stdcall timeGetDevCaps(ptr long) +@ stdcall timeGetSystemTime(ptr long) +@ stdcall timeGetTime() +@ stdcall timeKillEvent(long) +@ stdcall timeSetEvent(long long ptr long long) +@ stdcall waveInAddBuffer(long ptr long) +@ stdcall waveInClose(long) +@ stdcall waveInGetDevCapsA(long ptr long) +@ stdcall waveInGetDevCapsW(long ptr long) +@ stdcall waveInGetErrorTextA(long ptr long) +@ stdcall waveInGetErrorTextW(long ptr long) +@ stdcall waveInGetID(long ptr) +@ stdcall waveInGetNumDevs() +@ stdcall waveInGetPosition(long ptr long) +@ stdcall waveInMessage(long long long long) +@ stdcall waveInOpen(ptr long ptr long long long) +@ stdcall waveInPrepareHeader(long ptr long) +@ stdcall waveInReset(long) +@ stdcall waveInStart(long) +@ stdcall waveInStop(long) +@ stdcall waveInUnprepareHeader(long ptr long) +@ stdcall waveOutBreakLoop(long) +@ stdcall waveOutClose(long) +@ stdcall waveOutGetDevCapsA(long ptr long) +@ stdcall waveOutGetDevCapsW(long ptr long) +@ stdcall waveOutGetErrorTextA(long ptr long) +@ stdcall waveOutGetErrorTextW(long ptr long) +@ stdcall waveOutGetID(long ptr) +@ stdcall waveOutGetNumDevs() +@ stdcall waveOutGetPitch(long ptr) +@ stdcall waveOutGetPlaybackRate(long ptr) +@ stdcall waveOutGetPosition(long ptr long) +@ stdcall waveOutGetVolume(long ptr) +@ stdcall waveOutMessage(long long long long) +@ stdcall waveOutOpen(ptr long ptr long long long) +@ stdcall waveOutPause(long) +@ stdcall waveOutPrepareHeader(long ptr long) +@ stdcall waveOutReset(long) +@ stdcall waveOutRestart(long) +@ stdcall waveOutSetPitch(long long) +@ stdcall waveOutSetPlaybackRate(long long) +@ stdcall waveOutSetVolume(long long) +@ stdcall waveOutUnprepareHeader(long ptr long) +@ stdcall waveOutWrite(long ptr long) +@ stub winmmf_ThunkData32 +@ stub winmmsl_ThunkData32 diff --git a/reactos/lib/winmm/winmm_Cs.rc b/reactos/lib/winmm/winmm_Cs.rc new file mode 100644 index 00000000000..ff79e78c4d5 --- /dev/null +++ b/reactos/lib/winmm/winmm_Cs.rc @@ -0,0 +1,128 @@ +/* + * Czech resources for winmm + * Copyright 1999 Eric Pouech + * Copyright 2004 David Kredba + * + * 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 + */ + +STRINGTABLE LANGUAGE LANG_CZECH, SUBLANG_NEUTRAL +BEGIN + +/* MMSYS errors */ +MMSYSERR_NOERROR, "Urиenэ pшнkaz byl proveden." +MMSYSERR_ERROR, "Nedefinovanб vnмj№н chyba." +MMSYSERR_BADDEVICEID, "Pouѕitй ID zaшнzenн je mimo moѕnosti systйmu." +MMSYSERR_NOTENABLED, "Ovladaи nebyl povolen." +MMSYSERR_ALLOCATED, "Zaшнzenн je dosud pouѕнvбno. Vyиkejte na jeho uvolnмnн a zkuste to znovu." +MMSYSERR_INVALHANDLE, "Ukazatel na zaшнzenн je neplatnэ." +MMSYSERR_NODRIVER, "V systйmu nenн nainstalovбn ѕбdnэ ovladaи !\n" +MMSYSERR_NOMEM, "Nenн dost pamмti pro tuto ъlohu. Ukonиete jednu nebo vнc aplikacн k zнskбnн vнce volnй pamмti a zkuste to znovu." +MMSYSERR_NOTSUPPORTED, "Tato funkce nenн podporovбna. Pouѕijte funkci Capabilities k urиenн, jakй funkce a zprбvy ovladaи podporuje." +MMSYSERR_BADERRNUM, "Uvedenй инslo chyby nenн v systйmu definovбno." +MMSYSERR_INVALFLAG, "Systйmovй funkci byl pшedбn neplatnэ pшнznak." +MMSYSERR_INVALPARAM, "Systйmovй funkci byl pшedбn neplatnэ parametr." + +/* WAVE errors */ +WAVERR_BADFORMAT, "Tento formбt nenн podporovбn nebo nemщѕe bэt pшeloѕen. Pouѕijte funkci Capabilities k urиenн podporovanйho formбtu." +WAVERR_STILLPLAYING, "Nemohu provйst tuto operaci dokud jsou data pшehrбvбna. Zresetujte multimediбlnн zaшнzenн nebo vyиkejte na konec pшehrбvбnн." +WAVERR_UNPREPARED, "Wave hlaviиka nebyla pшipravena. Pouѕijte funkci Prepare k jejн konstrukci a pak to zkuste znovu." +WAVERR_SYNC, "Nemohu otevшнt zaшнzenн bez pouѕitн pшнznaku WAVE_ALLOWSYNC. Pouѕijte ho a zkuste to znovu." + +/* MIDI errors */ +MIDIERR_UNPREPARED, "MIDI hlaviиka nebyla pшipravena. Pouѕijte funkci Prepare k jejн konstrukci a pak to zkuste znovu." +MIDIERR_STILLPLAYING, "Nemohu provйst tuto operaci dokud jsou data pшehrбvбna. Zresetujte multimediбlnн zaшнzenн nebo vyиkejte na konec pшehrбvбnн." +MIDIERR_NOMAP, "MIDI map nebyla nalezena. To mщѕe ukazovat na problйm s ovladaиem nebo je soubor MIDIMAP.CFG po№kozen иi chybн." +MIDIERR_NOTREADY, "Port pшenб№н data na zaшнzenн. Poиkejte na dokonиenн pшenosu a zkuste to znovu." +MIDIERR_NODEVICE, "Souиasnй nastavenн MIDI mapperu se odkazuje na MIDI zaшнzenн nepшнtomnй v systйmu. Upravte nastavenн MIDI mapperu." +MIDIERR_INVALIDSETUP, "Souиasnй nastavenн MIDI je po№kozenй. Pшepi№te soubor MIDIMAP.CFG ve Windows sloѕce SYSTEM originбlem a zkuste to znovu." + +/* MCI errors */ +MCIERR_INVALID_DEVICE_ID, "Neplatnэ identifikбtor MCI zaшнzenн. Pouѕijte identifikбtor vrбcenэ pшi otevшenн MCI zaшнzenн." +MCIERR_UNRECOGNIZED_KEYWORD, "Ovladaи nepшipou№tн pouѕitэ parametr pшнkazu." +MCIERR_UNRECOGNIZED_COMMAND, "Ovladaи nepшipou№tн pouѕitэ pшнkaz." +MCIERR_HARDWARE, "S multimediбlnнm zaшнzenнm nмco nenн v poшбdku. Ujistмte se, ѕe pracuje jak mб, pшнpadnм oslovte jeho vэrobce." +MCIERR_INVALID_DEVICE_NAME, "Uvedenй zaшнzenн nenн pouѕitelnй nebo nenн podporovanй MCI." +MCIERR_OUT_OF_MEMORY, "Nenн dost pamмti na provedenн tйto ъlohy. \nUkonиete jednu nebo vнc aplikacн a zkuste to znovu." +MCIERR_DEVICE_OPEN, "Jmйno zaшнzenн uѕ je pouѕito jako alias touto aplikacн. Pouѕijte unikбtnн alias." +MCIERR_CANNOT_LOAD_DRIVER, "Vyskytl se nerozpoznatelnэ problйm pшi zavбdмnн uvedenйho ovladaиe." +MCIERR_MISSING_COMMAND_STRING, "Nebyl zadбn ѕбdnэ pшнkaz." +MCIERR_PARAM_OVERFLOW, "Vэstupnн шetмzec se nevejde do vэstupnнho zбsobnнku. Zvмt№ete velikost zбsobnнku." +MCIERR_MISSING_STRING_ARGUMENT, "Tento pшнkaz vyѕaduje textovэ parametr. Zadejte jeden." +MCIERR_BAD_INTEGER, "Toto инslo je neplatnй pro tento pшнkaz." +MCIERR_PARSER_INTERNAL, "Ovladaи zaшнzenн vrбtil neplatnэ nбvratovэ typ. Zeptejte se dodavatele zaшнzenн na novэ ovladaи." +MCIERR_DRIVER_INTERNAL, "Byl rozpoznбn problйm s ovladaиem. Zнskejte od vэrobce novэ ovladaи." +MCIERR_MISSING_PARAMETER, "Tento pшнkaz vyѕaduje parametr. Zadejte ho." +MCIERR_UNSUPPORTED_FUNCTION, "Vбmi pouѕitй MCI zaшнzenн nepodporuje uvedenэ pшнkaz." +MCIERR_FILE_NOT_FOUND, "Soubor nebyl nalezen. Ujistмte se, ѕe cesta k souboru a jeho jmйno jsou platnй." +MCIERR_DEVICE_NOT_READY, "Ovladaи zaшнzenн nenн pшipraven." +MCIERR_INTERNAL, "Pшi inicialiazaci MCI do№lo k problйmщm. Zkuste zrestartovat Windows." +MCIERR_DRIVER, "Ovladaи mб problйmy a ukonиil svou иinnost. Ovladaи nevrбtil popis chyby." +MCIERR_CANNOT_USE_ALL, "Nemohu pouѕнt 'all' jako jmйno zaшнzenн pшi provбdмnн tohoto pшнkazu." +MCIERR_MULTIPLE, "Vyskytly se chyby na vнce zaшнzenнch. Zadejte pшнkazy zvlб№» pro kaѕdй jedno zaшнzenнify, aby bylo zji№tмno, kterй zaшнzenн chybuje." +MCIERR_EXTENSION_NOT_FOUND, "Nedokбѕi pшiшadit soubor s touto pшнponou vhodnйmu zaшнzenн." +MCIERR_OUTOFRANGE, "Uvedenэ parametr je mimo meze uvedenйho pшнkazu." +MCIERR_FLAGS_NOT_COMPATIBLE, "Tyto parametry nemohou bэt poѕity spolu." +MCIERR_FILE_NOT_SAVED, "Nemohu uloѕit soubor. Ujistмte se, ѕe je dost mнsta na disku nebo je-li Va№e sн»ovй pшipojenн prщchozн." +MCIERR_DEVICE_TYPE_REQUIRED, "Nemohu najнt poѕadovanй zaшнzenн. Ujistмte se, ѕe je nainstalovбno, nebo ѕe jste jeho nбzev uvedli pшesnм." +MCIERR_DEVICE_LOCKED, "Toto zaшнzenн je prбvм uzavнrбno. Vyиkejte nмkolik sekund a zkuste to znovu." +MCIERR_DUPLICATE_ALIAS, "Tento alias je uѕ pouѕнvбn v tйto aplikaci. Pouѕijte jinй jmйno." +MCIERR_BAD_CONSTANT, "Uvedenэ parametr je neplatnэ pro tento pшнkaz." +MCIERR_MUST_USE_SHAREABLE, "Uvedenй zaшнzenн je uѕ pouѕнvбno. Chcete-li ho sdнlet, pouѕijte 'shareable' parametr s kaѕdэm pшнkazem 'open'." +MCIERR_MISSING_DEVICE_NAME, "Tento pшнkaz vyѕaduje alias, soubor, ovladaи nebo nбzev zaшнzenн. Uveпte jeden prosнm." +MCIERR_BAD_TIME_FORMAT, "Pouѕitэ formбt иasu je neplatnэ. Nahlйdnмte do MCI dokumentace a zjistмte si platnй formбty." +MCIERR_NO_CLOSING_QUOTE, "Hodnota parametru nenн uzavшena uvozovkami. Doplтte je." +MCIERR_DUPLICATE_FLAGS, "Parametr nebo hodnota byla zadбna dvakrбt. Zadejte jen jeden/jednu." +MCIERR_INVALID_FILE, "Tento soubor nemщѕe bэt pшehrбn na tomto MCI zaшнzenн. Soubor mщѕe bэt po№kozen nebo nemб sprбvnэ formбt." +MCIERR_NULL_PARAMETER_BLOCK, "MCI byl pшedбn prбzdnэ blok parametrщ." +MCIERR_UNNAMED_RESOURCE, "Nemohu uloѕit soubor bez nбzvu. Zadejte nбzev." +MCIERR_NEW_REQUIRES_ALIAS, "Pшi pouѕitн parametru 'new' musнte zadat alias." +MCIERR_NOTIFY_ON_AUTO_OPEN, "Nelze pouѕнt parametr 'notify' s automaticky otevшenэm zaшнzenнm." +MCIERR_NO_ELEMENT_ALLOWED, "Nelze pouѕнt soubor s tнmto zaшнzenнm." +MCIERR_NONAPPLICABLE_FUNCTION, "Nelze dokonиit skupinu pшнkazщ v tomto poшadн. Opravte poшadн pшнkazщ a zkuste to znovu." +MCIERR_ILLEGAL_FOR_AUTO_OPEN, "Tento pшнkaz nelze dokonиit na automaticky otevшenйm zaшнzenн. Vyиkejte na zavшenн zaшнzenн a zkuste to znovu." +MCIERR_FILENAME_REQUIRED, "Nбzev souboru je neplatnэ. Ujistмte se, ѕe nбzev souboru mб 8 znakщ nбsledovanэch teиkou a pшнponou." +MCIERR_EXTRA_CHARACTERS, "Nelze zadat znaky za шetмzec uzavшenэ uvozovkami." +MCIERR_DEVICE_NOT_INSTALLED, "Toto zaшнzenн nenн v systйmu nainstalovбno. Nainstalujte ho v Ovlбdacнm panelu, na zбloѕce Ovladaиe." +MCIERR_GET_CD, "Nemohu pшistoupit k uvedenйmu souboru nebo MCI zaшнzenн. Zmмтte adresбш nebo restartujte Vб№ poинtaи." +MCIERR_SET_CD, "Nemohu pшistoupit k uvedenйmu souboru nebo MCI zaшнzenн, protoѕe aplikace nemщѕe zmмnit adresбш." +MCIERR_SET_DRIVE, "Nemohu pшistoupit k uvedenйmu souboru nebo MCI zaшнzenн, protoѕe aplikace nemщѕe zmмnit jednotku disku." +MCIERR_DEVICE_LENGTH, "Urиete zaшнzenн nebo ovladaи jehoѕ nбzev je krat№н neѕ 79 znakщ." +MCIERR_DEVICE_ORD_LENGTH, "Urиete zaшнzenн nebo ovladaи jehoѕ nбzev je krat№н neѕ 69 znakщ." +MCIERR_NO_INTEGER, "Tento pшнkaz vyѕaduje celoинselnэ parametr. Pouѕijte ho prosнm." +MCIERR_WAVE_OUTPUTSINUSE, "V№echna wave zaшнzenн, kterб by mohla pшehrбt soubory s tнmto formбtem jsou pouѕнvбna. Vyиkejte na uvolnмnн zaшнzenн a zkuste to znovu." +MCIERR_WAVE_SETOUTPUTINUSE, "Nemohu nastavit toto wave zaшнzenн na playback, jelikoѕ je pouѕнvбno. Vyиkejte na uvolnмnн zaшнzenн a zkuste to znovu." +MCIERR_WAVE_INPUTSINUSE, "V№echna wave zaшнzenн, kterб by mohla nahrбvat oubory s tнmto formбtem jsou pouѕнvбna. Vyиkejte na uvolnмnн zaшнzenн a zkuste to znovu." +MCIERR_WAVE_SETINPUTINUSE, "Nemohu nastavit toto wave zaшнzenн na nahrбvбnн, jelikoѕ je pouѕнvбno. Vyиkejte na uvolnмnн zaшнzenн a zkuste to znovu." +MCIERR_WAVE_OUTPUTUNSPECIFIED, "Jakйkoliv waveform kompatibilnн pшehrбvacн zaшнzenн mщѕe bэt pouѕito." +MCIERR_WAVE_INPUTUNSPECIFIED, "Jakйkoliv waveform kompatibilnн nahrбvacн zaшнzenн mщѕe bэt pouѕito." +MCIERR_WAVE_OUTPUTSUNSUITABLE, "Nenн nainstalovбno ѕбdnй wave zaшнzenн, kterй by bylo schopno pшehrбt soubory v tomto formбtu. Pouѕijte zбloѕku Ovladaиe k instalaci wave zaшнzenн." +MCIERR_WAVE_SETOUTPUTUNSUITABLE,"Pшehrбvacн zaшнzenн nedokбzalo rozpoznat formбt souboru." +MCIERR_WAVE_INPUTSUNSUITABLE, "Nenн nainstalovбno ѕбdnй wave zaшнzenн, kterй by bylo schopno nahrбt soubory v tomto formбtu. Pouѕijte zбloѕku Ovladaиe k instalaci wave zaшнzenн." +MCIERR_WAVE_SETINPUTUNSUITABLE, "Zaшнzenн, ze kterйho zkou№нte nahrбvat, nedokбѕe rozpoznat formбt vэstupnнho souboru." +MCIERR_NO_WINDOW, "Okno display chybн." +MCIERR_CREATEWINDOW, "Nemohu vytvoшit nebo pouѕнt okno." +MCIERR_FILE_READ, "Nemohu pшeинst zadanэ soubor. Ujistмte se, ѕe soubor stбle existuje a zkontrolujte svщj disk nebo sн»ovou konektivitu." +MCIERR_FILE_WRITE, "Nemohu zapisovat do zadanйho souboru. Ujistмte se, ѕe mбte dost mнsta na disku nebo zda jste pшipojeni k sнti." +MCIERR_SEQ_DIV_INCOMPATIBLE, "Formбty иasu ""song pointer"" a SMPTE jsou vzбjemnм vэluиnй. Nemщѕete je pouѕнt souиasnм." +MCIERR_SEQ_NOMIDIPRESENT, "V systйmu nejsou nainstalovбny MIDI zaшнzenн. Nainstalujte je ze zбloѕky Ovladaи v Ovlбdacнm panelu." +MCIERR_SEQ_PORT_INUSE, "Tento MIDI port je pouѕнvбn. Vyиkejte na jeho uvolnмnн; pak to zkuste znovu." +MCIERR_SEQ_PORT_MAPNODEVICE, "Nastavenн MIDI mapperu odkazuje na MIDI zaшнzenн, kterй nenн v systйmu nainstalovбno. Nainstalujte ho pomocн zбloѕky MIDI Mapper v Ovlбdacнm panelu." +MCIERR_SEQ_PORT_MISCERROR, "Nastala chyba pшi prбci s tнmto portem." +MCIERR_SEQ_PORT_NONEXISTENT, "Toto MIDI zaшнzenн nenн nainstalovбno v systйmu. Nainstalujte ho v Ovlбdacнm panelu na zбloѕce Driver." +MCIERR_SEQ_PORTUNSPECIFIED, "Systйm neznб tento MIDI port." +MCIERR_SEQ_TIMER, "V№echny иasovaиe multimйdiн jsou pouѕнvбny aplikacemi. Ukonиete jednu z tмchto aplikacн a zkuste to znovu." + +END diff --git a/reactos/lib/winmm/winmm_De.rc b/reactos/lib/winmm/winmm_De.rc new file mode 100644 index 00000000000..9f7c8b9051b --- /dev/null +++ b/reactos/lib/winmm/winmm_De.rc @@ -0,0 +1,126 @@ +/* + * Copyright 2004 Henning Gerhardt + * + * 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 + */ + +STRINGTABLE LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT +BEGIN + +/* MMSYS errors */ +MMSYSERR_NOERROR, "Der angeforderte Befehl wurde ausgefьhrt." +MMSYSERR_ERROR, "Unbekannter externer Fehler." +MMSYSERR_BADDEVICEID, "Die derzeit verwendete Gerдtekennung ist auЯerhalb des zulдssigen Bereichs fьr Ihr System." +MMSYSERR_NOTENABLED, "Der Treiber konnte nicht gestartet werden." +MMSYSERR_ALLOCATED, "Das Gerдt wird bereits verwendet. Warten Sie, bis es freigegeben ist, und versuchen Sie es erneut." +MMSYSERR_INVALHANDLE, "Das angegebende Gerдtehandle ist ungьltig." +MMSYSERR_NODRIVER, "Es ist kein Treiber auf Ihrem System installiert !\n" +MMSYSERR_NOMEM, "Nicht genьgend Speicher fьr diesen Befehl. Beenden Sie eine oder mehrere Anwendungen, und versuchen Sie es erneut." +MMSYSERR_NOTSUPPORTED, "Diese Funktion wird nicht unterstьtzt. Benutzen Sie die Funktion 'Capabilities', um zu ermitteln, welche Funktion dieser Treiber unterstьtzt." +MMSYSERR_BADERRNUM, "Die angegebene Fehlernummer ist fьr dieses System nicht definiert." +MMSYSERR_INVALFLAG, "Ein ungьltiges Flag wurde an eine Systemfunktion ьbergeben." +MMSYSERR_INVALPARAM, "Ein ungьltiger Parameter wurde an eine Systemfunktion ьbergeben." + +/* WAVE errors */ +WAVERR_BADFORMAT, "Dieses Format wird nicht unterstьtzt oder kann nicht ьbersetzt werden. Benutzen Sie die Funktion 'Capabilities', um die unterstьtzten Formate zu ermitteln." +WAVERR_STILLPLAYING, "Die Funktion kann nicht durchgefьhrt werden, wenn noch Mediendateien wiedergegeben werden. Starten Sie das Gerдt neu, oder warten Sie bis keine Daten mehr wiedergegeben werden." +WAVERR_UNPREPARED, "Der WAVE - Header wurde nicht vorbereitet. Benutzen Sie die Funktion 'Prepare' zum Vorbereiten des Headers und versuchen Sie es erneut." +WAVERR_SYNC, "Das Gerдt kann nicht ohne das WAVE_ALLOWSYNC - Flag geцffnet werden. Benutzen Sie dieses Flag und versuchen Sie es erneut." + +/* MIDI errors */ +MIDIERR_UNPREPARED, "Der MIDI - Header wurde nicht vorbereitet. Benutzen Sie die Funktion 'Prepare' zum Vorbereiten des Headers und versuchen Sie es erneut." +MIDIERR_STILLPLAYING, "Die Funktion kann nicht durchgefьhrt werden, wenn noch Mediendateien wiedergegeben werden. Starten Sie das Gerдt neu, oder warten Sie bis keine Daten mehr wiedergegeben werden." +MIDIERR_NOMAP, "Es wurde keine MIDI - Map gefunden. Es kцnnte ein Problem mit dem Treiber geben oder die Datei MIDIMAP.CFG fehlt oder ist beschдdigt." +MIDIERR_NOTREADY, "Der Anschluss ist mit der Datenausgabe belegt. Warten Sie, bis die Daten ьbertragen wurden und versuchen Sie es erneut." +MIDIERR_NODEVICE, "Das gegenwдrtige MIDI - Mapper Setup benutzt ein MIDI - Gerдt, das nicht installiert ist. Benutzen Sie den MIDI - Mapper, um das Setup zu дndern." +MIDIERR_INVALIDSETUP, "Das aktuelle MIDI Setup ist beschдdigt. Kopieren sie die ursprьngliche Datei MIDIMAP.CFG ind das Windows - Systemverzeichnis und versuchen Sie es erneut." + +/* MCI errors */ +MCIERR_INVALID_DEVICE_ID, "Ungьltige MCI - Gerдtekennung. Benutzen Sie die zurьckgegebene ID, wenn Sie das MCI - Gerдt цffnen." +MCIERR_UNRECOGNIZED_KEYWORD, "Der Treiber kann den angegebenen Befehlsparameter nicht anerkennen." +MCIERR_UNRECOGNIZED_COMMAND, "Der Treiber kann den angegebenen Befehl nicht anerkennen." +MCIERR_HARDWARE, "Es gibt ein Problem mit Ihrem Media - Gerдt. Stellen Sie sicher, dass es richtig arbeitet oder fragen Sie den Gerдtehersteller." +MCIERR_INVALID_DEVICE_NAME, "Das angegebene Gerдt ist nicht geцffnet oder wird vom MCI nicht erkannt." +MCIERR_OUT_OF_MEMORY, "Nicht genьgend Speicher fьr den angeforderten Vorgang. \nBeenden Sie eine oder mehrere Anwendungen, und versuchen Sie es erneut." +MCIERR_DEVICE_OPEN, "Der Gerдtename wird von dieser Anwendung bereits als Alias benutzt. Benutzen Sie einen eindeutigen Alias" +MCIERR_CANNOT_LOAD_DRIVER, "Es gibt ein unbekanntes Problem beim Laden des angegebenen Gerдtetreibers." +MCIERR_MISSING_COMMAND_STRING, "Kein Befehl wurde angegeben." +MCIERR_PARAM_OVERFLOW, "Die Ausgabezeichenkennte war zu lang fьr den Rьckgabepuffer. Erhцhen Sie die PuffergrцЯe." +MCIERR_MISSING_STRING_ARGUMENT, "Der Befehl erfordert einen Zeichenkettenparameter. Bitte stellen Sie einen bereit." +MCIERR_BAD_INTEGER, "Die Angabe einer ganzen Zahl ist fьr diesen Befehl ungьltig." +MCIERR_PARSER_INTERNAL, "Der Gerдtetreiber hat einen ungьltigen Rьckgabewert geliefert. Fragen Sie den Gerдtehersteller nach einem neuen Treiber." +MCIERR_DRIVER_INTERNAL, "Ein Treiberfehler ist aufgetreten. Fragen Sie den Gerдtehersteller nach einem neuen Treiber." +MCIERR_MISSING_PARAMETER, "Der angegebene Befehl erfordert einen Parameter. Bitte geben Sie einen an." +MCIERR_UNSUPPORTED_FUNCTION, "Das verwendete MCI - Gerдt unterstьtzt diesen Befehl nicht." +MCIERR_FILE_NOT_FOUND, "Die angeforderte Datei wurde nicht gefunden. Stellen Sie sicher, dass Pfad- und Dateiname richtig sind." +MCIERR_DEVICE_NOT_READY, "Der Gerдtetreiber ist nicht bereit." +MCIERR_INTERNAL, "Ein Fehler ereignete sich beim Starten von MCI. Versuche Windows neu zu starten." +MCIERR_DRIVER, "Es gibt ein Problem mit dem Gerдtetreiber. Der Treiber wird geschlossen. Ein Fehler kann nicht gemeldet werden." +MCIERR_CANNOT_USE_ALL, "Der Gerдtename 'all' ist nicht in diesem Befehl erlaubt." +MCIERR_MULTIPLE, "Es traten Fehler in mehr als einem Gerдt auf. Geben Sie jeden Befehl fьr jedes Gerдt einzeln an, um zu bestimmen, welches Gerдt die Fehler verursachte." +MCIERR_EXTENSION_NOT_FOUND, "Kann keinen Gerдtetyp aus der angegebenen Dateinamenerweiterung ermitteln." +MCIERR_OUTOFRANGE, "Der angegebene Paramter liegt auЯerhalb des zulдssigen Bereichs fьr diesen Befehl." +MCIERR_FLAGS_NOT_COMPATIBLE, "Die Paramter kцnnen nicht zusammen verwendet werden." +MCIERR_FILE_NOT_SAVED, "Die Datei kann nicht gespeichert werden. Stellen Sie sicher, dass genьgend Platz auf dem Datentrдger verfьgbar ist oder Ihre Netzwerkverbindung noch besteht." +MCIERR_DEVICE_TYPE_REQUIRED, "Das angegebene Gerдt wurde nicht gefunden. Stellen Sie sicher, dass es installiert ist oder der Gerдtename richtig geschrieben ist." +MCIERR_DEVICE_LOCKED, "Das angegebene Gerдt wird geschlossen. Warten Sie einige Sekunden, und versuchen Sie es erneut." +MCIERR_DUPLICATE_ALIAS, "Der angegebene Alias wird von dieser Anwendung bereits verwendet. Wдhlen Sie einen eindeutigen Alias." +MCIERR_BAD_CONSTANT, "Der angegebene Parameter fьr diesen Befehl ungьltig." +MCIERR_MUST_USE_SHAREABLE, "Das Gerдt ist bereits geцffnet. Benutzen Sie den 'shareable' - Parameter bei jedem 'open' - Befehl." +MCIERR_MISSING_DEVICE_NAME, "Der angegebene Befehl erfordert einen Alias-, Datei-, Treiber- oder Gerдtenamen. Bitte geben Sie einen an." +MCIERR_BAD_TIME_FORMAT, "Der angegebene Wert fьr das Zeitformat ist ungьltig. Lesen Sie in der MCI - Dokumentation nach gьltigen Formaten nach." +MCIERR_NO_CLOSING_QUOTE, "Ein abschlieЯendes Anfьhrungszeichen fehlt im Parameter. Bitte geben Sie eins an." +MCIERR_DUPLICATE_FLAGS, "Ein Parameter oder Wert wurde zweimal angegeben. Geben Sie in nur einzeln an." +MCIERR_INVALID_FILE, "Die angegebene Datei kann auf dem MCI - Gerдt nicht wiedergegeben werden. Die Datei ist wahrscheinlich beschдdigt oder in einem ungьltigen Format." +MCIERR_NULL_PARAMETER_BLOCK, "Der Parameterblock, der zu MCI ьbergeben wurde, war NULL." +MCIERR_UNNAMED_RESOURCE, "Es kann keine unbenannte Datei gespeichert werden. Geben Sie einen Dateinamen an." +MCIERR_NEW_REQUIRES_ALIAS, "Sie mьssen einen Alias mit dem 'new' - Parameter angeben." +MCIERR_NOTIFY_ON_AUTO_OPEN, "Das 'notify' Flag ist unzulдssig fьr selbstцffnende Gerдte." +MCIERR_NO_ELEMENT_ALLOWED, "Ein Dateiname kann mit diesem Gerдt nicht verwendet werden." +MCIERR_NONAPPLICABLE_FUNCTION, "Die Befehle sind in der angegebenen Reihenfolge nicht ausfьhrbar. Дndern Sie die Reihenfolge, und versuchen Sie es erneut." +MCIERR_ILLEGAL_FOR_AUTO_OPEN, "Der Befehl kann nicht auf ein selbstцffnedes Gerдt angewandt werden. Warten Sie, bis das Gerдt geschlossen wurde und versuchen Sie es erneut." +MCIERR_FILENAME_REQUIRED, "Der Dateiname ist ungьltig. Der Dateiname muss aus maximal 8 Zeichen, gefolgt von einem Punkt und einer Dateinamenerweiterung bestehen." +MCIERR_EXTRA_CHARACTERS, "Zusдtzliche Zeichen nach einer Zeichenkette mit Anfьhrungszeichen sind nicht erlaubt." +MCIERR_DEVICE_NOT_INSTALLED, "Das angegebene Gerдt ist nicht auf Ihren System installiert. Benutzen Sie die Hardwareerkennung in der Systemsteuerung, um das Gerдt zu installieren." +MCIERR_GET_CD, "Auf die angegebene Datei oder das MCI - Gerдt kann nicht zugegriffen werden. Versuchen Sie, das Verzeichnis zu wechseln oder das System neu zu starten." +MCIERR_SET_CD, "Auf die angegebene Datei oder das MCI - Gerдt kann nicht zugegriffen werden, weil die Anwendung nicht das Verzeichnis wechseln kann." +MCIERR_SET_DRIVE, "Auf die angegebene Datei oder das MCI - Gerдt kann nicht zugegriffen werden, weil die Anwendung nicht das Laufwerk wechseln kann." +MCIERR_DEVICE_LENGTH, "Geben Sie einen Gerдte- oder Treibernamen mit weniger als 79 Zeichen an." +MCIERR_DEVICE_ORD_LENGTH, "Geben Sie einen Gerдte- oder Treibernamen mit weniger als 69 Zeichen an." +MCIERR_NO_INTEGER, "Der angegebene Befehl erfordert einen ganzzahligen Parameter. Bitte geben Sie einen an." +MCIERR_WAVE_OUTPUTSINUSE, "Alle Waveformgerдte, die diese Dateien in dem gegenwдrtigen Format wiedergeben kцnnten, sind in Benutzung. Warten Sie, bis ein Waveformgerдt frei ist, und wiederholen Sie den Vorgang." +MCIERR_WAVE_SETOUTPUTINUSE, "Das gegenwдrtige Waveformgerдt kann nicht wiedergeben, weil es gerade benutzt wird. Warten Sie, bis das Gerдt frei ist, und wiederholen Sie den Vorgang." +MCIERR_WAVE_INPUTSINUSE, "Es ist kein Waveformgerдt frei, das das gegenwдrtige Format aufzeichnen kцnnte. Warten Sie, bis ein Waveformgerдt frei ist, und wiederholen Sie den Vorgang." +MCIERR_WAVE_SETINPUTINUSE, "Das gegenwдrtige Waveformgerдt kann nicht aufzeichnen, weil es gerade verwendet wird. Warten Sie, bis das Gerдt frei ist, und wiederholen Sie den Vorgang." +MCIERR_WAVE_OUTPUTUNSPECIFIED, "Jedes kompatible Waveform - Wiedergabegerдt kann verwendet werden." +MCIERR_WAVE_INPUTUNSPECIFIED, "Jedes kompatible Waveform - Aufnahmegerдt kann verwendet werden." +MCIERR_WAVE_OUTPUTSUNSUITABLE, "Es ist kein Waveformgerдt installiert, das Dateien im aktuellen Format wiedergeben kann. Benutzen Sie die Hardwareerkennung in der Systemsteuerung, um ein Waveformgerдt zu installieren." +MCIERR_WAVE_SETOUTPUTUNSUITABLE,"Das Wiedergabegerдt erkennt das gegenwдrtige Dateiformat nicht." +MCIERR_WAVE_INPUTSUNSUITABLE, "Es ist kein Waveformgerдt installiert, das Dateien im aktuellen Format aufnehmen kann. Benutzen Sie die Hardwareerkennung in der Systemsteuerung, um ein Waveformgerдt zu installieren." +MCIERR_WAVE_SETINPUTUNSUITABLE, "Das Gerдt, mit dem Sie aufzeichnen mцchten, erkennt das gegenwдrtige Dateiformat nicht." +MCIERR_NO_WINDOW, "Es gibt kein Anzeigefenster." +MCIERR_CREATEWINDOW, "Fenster konnte nicht erzeugt oder verwendet werden." +MCIERR_FILE_READ, "Die Datei konnte nicht gelesen werden. Stellen Sie sicher, dass die Datei existiert oder Ihre Netzwerkverbindung noch besteht." +MCIERR_FILE_WRITE, "Die Datei konnte nicht geschrieben werden. Stellen Sie sicher, dass genьgend Platz auf dem Datentrдger verfьgbar ist, oder dass die Netzwerkverbindung noch besteht." +MCIERR_SEQ_DIV_INCOMPATIBLE, "Die Zeitformate von ""song pointer"" und SMPTE schliessen sich gegenseitig aus. Sie kцnnen sie nicht zusammen verwenden." +MCIERR_SEQ_NOMIDIPRESENT, "Es sind keine MIDI - Gerдte auf dem System installiert. Benutzen Sie die Hardwareerkennung in der Systemsteuerung, um einen MIDI - Treiber zu installieren." +MCIERR_SEQ_PORT_INUSE, "Der angegebene MIDI - Anschluss wird bereits verwendet. Warten Sie bis der Anschluss frei ist, und versuchen Sie es erneut." +MCIERR_SEQ_PORT_MAPNODEVICE, "Das gegenwдrtige MIDI - Mapper Setup benutzt ein MIDI - Gerдt, dass nicht auf Ihren System installiert ist. Benutzen Sie den MIDI - Mapper in der Systemsteuerung, um das Setup zu дndern." +MCIERR_SEQ_PORT_MISCERROR, "Beim Benutzen des angegebenen Anschlusses trat ein Fehler auf." +MCIERR_SEQ_PORT_NONEXISTENT, "Es sind keine angegebnen MIDI - Gerдte auf dem System installiert. Benutzen Sie die Hardwareerkennung in der Systemsteuerung, um ein MIDI - Gerдt zu installieren." +MCIERR_SEQ_PORTUNSPECIFIED, "Es gibt keinen aktuellen MIDI - Anschluss auf dem System." +MCIERR_SEQ_TIMER, "Alle Multimediazeitgeber werden von anderen Anwendungen verwendet. Beenden Sie eine dieser Anwendungen, und versuchen Sie es erneut." + +END diff --git a/reactos/lib/winmm/winmm_En.rc b/reactos/lib/winmm/winmm_En.rc new file mode 100644 index 00000000000..cb3ffc922b1 --- /dev/null +++ b/reactos/lib/winmm/winmm_En.rc @@ -0,0 +1,126 @@ +/* + * 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 + */ + +STRINGTABLE LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL +BEGIN + +/* MMSYS errors */ +MMSYSERR_NOERROR, "The specified command was carried out." +MMSYSERR_ERROR, "Undefined external error." +MMSYSERR_BADDEVICEID, "A device ID has been used that is out of range for your system." +MMSYSERR_NOTENABLED, "The driver was not enabled." +MMSYSERR_ALLOCATED, "The specified device is already in use. Wait until it is free, and then try again." +MMSYSERR_INVALHANDLE, "The specified device handle is invalid." +MMSYSERR_NODRIVER, "There is no driver installed on your system !\n" +MMSYSERR_NOMEM, "Not enough memory available for this task. Quit one or more applications to increase available memory, and then try again." +MMSYSERR_NOTSUPPORTED, "This function is not supported. Use the Capabilities function to determine which functions and messages the driver supports." +MMSYSERR_BADERRNUM, "An error number was specified that is not defined in the system." +MMSYSERR_INVALFLAG, "An invalid flag was passed to a system function." +MMSYSERR_INVALPARAM, "An invalid parameter was passed to a system function." + +/* WAVE errors */ +WAVERR_BADFORMAT, "The specified format is not supported or cannot be translated. Use the Capabilities function to determine the supported formats" +WAVERR_STILLPLAYING, "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing." +WAVERR_UNPREPARED, "The wave header was not prepared. Use the Prepare function to prepare the header, and then try again." +WAVERR_SYNC, "Cannot open the device without using the WAVE_ALLOWSYNC flag. Use the flag, and then try again." + +/* MIDI errors */ +MIDIERR_UNPREPARED, "The MIDI header was not prepared. Use the Prepare function to prepare the header, and then try again." +MIDIERR_STILLPLAYING, "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing." +MIDIERR_NOMAP, "A MIDI map was not found. There may be a problem with the driver, or the MIDIMAP.CFG file may be corrupt or missing." +MIDIERR_NOTREADY, "The port is transmitting data to the device. Wait until the data has been transmitted, and then try again." +MIDIERR_NODEVICE, "The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use MIDI Mapper to edit the setup." +MIDIERR_INVALIDSETUP, "The current MIDI setup is damaged. Copy the original MIDIMAP.CFG file to the Windows SYSTEM directory, and then try again." + +/* MCI errors */ +MCIERR_INVALID_DEVICE_ID, "Invalid MCI device ID. Use the ID returned when opening the MCI device." +MCIERR_UNRECOGNIZED_KEYWORD, "The driver cannot recognize the specified command parameter." +MCIERR_UNRECOGNIZED_COMMAND, "The driver cannot recognize the specified command." +MCIERR_HARDWARE, "There is a problem with your media device. Make sure it is working correctly or contact the device manufacturer." +MCIERR_INVALID_DEVICE_NAME, "The specified device is not open or is not recognized by MCI." +MCIERR_OUT_OF_MEMORY, "Not enough memory available for this task. \nQuit one or more applications to increase available memory, and then try again." +MCIERR_DEVICE_OPEN, "The device name is already being used as an alias by this application. Use a unique alias." +MCIERR_CANNOT_LOAD_DRIVER, "There is an undetectable problem in loading the specified device driver." +MCIERR_MISSING_COMMAND_STRING, "No command was specified." +MCIERR_PARAM_OVERFLOW, "The output string was to large to fit in the return buffer. Increase the size of the buffer." +MCIERR_MISSING_STRING_ARGUMENT, "The specified command requires a character-string parameter. Please provide one." +MCIERR_BAD_INTEGER, "The specified integer is invalid for this command." +MCIERR_PARSER_INTERNAL, "The device driver returned an invalid return type. Check with the device manufacturer about obtaining a new driver." +MCIERR_DRIVER_INTERNAL, "There is a problem with the device driver. Check with the device manufacturer about obtaining a new driver." +MCIERR_MISSING_PARAMETER, "The specified command requires a parameter. Please supply one." +MCIERR_UNSUPPORTED_FUNCTION, "The MCI device you are using does not support the specified command." +MCIERR_FILE_NOT_FOUND, "Cannot find the specified file. Make sure the path and filename are correct." +MCIERR_DEVICE_NOT_READY, "The device driver is not ready." +MCIERR_INTERNAL, "A problem occurred in initializing MCI. Try restarting Windows." +MCIERR_DRIVER, "There is a problem with the device driver. The driver has closed. Cannot access error." +MCIERR_CANNOT_USE_ALL, "Cannot use 'all' as the device name with the specified command." +MCIERR_MULTIPLE, "Errors occurred in more than one device. Specify each command and device separately to determine which devices caused the error" +MCIERR_EXTENSION_NOT_FOUND, "Cannot determine the device type from the given filename extension." +MCIERR_OUTOFRANGE, "The specified parameter is out of range for the specified command." +MCIERR_FLAGS_NOT_COMPATIBLE, "The specified parameters cannot be used together." +MCIERR_FILE_NOT_SAVED, "Cannot save the specified file. Make sure you have enough disk space or are still connected to the network." +MCIERR_DEVICE_TYPE_REQUIRED, "Cannot find the specified device. Make sure it is installed or that the device name is spelled correctly." +MCIERR_DEVICE_LOCKED, "The specified device is now being closed. Wait a few seconds, and then try again." +MCIERR_DUPLICATE_ALIAS, "The specified alias is already being used in this application. Use a unique alias." +MCIERR_BAD_CONSTANT, "The specified parameter is invalid for this command." +MCIERR_MUST_USE_SHAREABLE, "The device driver is already in use. To share it, use the 'shareable' parameter with each 'open' command." +MCIERR_MISSING_DEVICE_NAME, "The specified command requires an alias, file, driver, or device name. Please supply one." +MCIERR_BAD_TIME_FORMAT, "The specified value for the time format is invalid. Refer to the MCI documentation for valid formats." +MCIERR_NO_CLOSING_QUOTE, "A closing double-quotation mark is missing from the parameter value. Please supply one." +MCIERR_DUPLICATE_FLAGS, "A parameter or value was specified twice. Only specify it once." +MCIERR_INVALID_FILE, "The specified file cannot be played on the specified MCI device. The file may be corrupt, or not in the correct format." +MCIERR_NULL_PARAMETER_BLOCK, "A null parameter block was passed to MCI." +MCIERR_UNNAMED_RESOURCE, "Cannot save an unnamed file. Supply a filename." +MCIERR_NEW_REQUIRES_ALIAS, "You must specify an alias when using the 'new' parameter." +MCIERR_NOTIFY_ON_AUTO_OPEN, "Cannot use the 'notify' flag with auto-opened devices." +MCIERR_NO_ELEMENT_ALLOWED, "Cannot use a filename with the specified device." +MCIERR_NONAPPLICABLE_FUNCTION, "Cannot carry out the commands in the order specified. Correct the command sequence, and then try again." +MCIERR_ILLEGAL_FOR_AUTO_OPEN, "Cannot carry out the specified command on an auto-opened device. Wait until the device is closed, and then try again." +MCIERR_FILENAME_REQUIRED, "The filename is invalid. Make sure the filename is not longer than 8 characters, followed by a period and an extension." +MCIERR_EXTRA_CHARACTERS, "Cannot specify extra characters after a string enclosed in quotation marks." +MCIERR_DEVICE_NOT_INSTALLED, "The specified device is not installed on the system. Use the Drivers option in Control Panel to install the device." +MCIERR_GET_CD, "Cannot access the specified file or MCI device. Try changing directories or restarting your computer." +MCIERR_SET_CD, "Cannot access the specified file or MCI device because the application cannot change directories." +MCIERR_SET_DRIVE, "Cannot access specified file or MCI device because the application cannot change drives." +MCIERR_DEVICE_LENGTH, "Specify a device or driver name that is less than 79 characters." +MCIERR_DEVICE_ORD_LENGTH, "Specify a device or driver name that is less than 69 characters." +MCIERR_NO_INTEGER, "The specified command requires an integer parameter. Please provide one." +MCIERR_WAVE_OUTPUTSINUSE, "All wave devices that can play files in the current format are in use. Wait until a wave device is free, and then try again." +MCIERR_WAVE_SETOUTPUTINUSE, "Cannot set the current wave device for play back because it is in use. Wait until the device is free, and then try again." +MCIERR_WAVE_INPUTSINUSE, "All wave devices that can record files in the current format are in use. Wait until a wave device is free, and then try again." +MCIERR_WAVE_SETINPUTINUSE, "Cannot set the current wave device for recording because it is in use. Wait until the device is free, and then try again." +MCIERR_WAVE_OUTPUTUNSPECIFIED, "Any compatible waveform playback device may be used." +MCIERR_WAVE_INPUTUNSPECIFIED, "Any compatible waveform recording device may be used." +MCIERR_WAVE_OUTPUTSUNSUITABLE, "No wave device that can play files in the current format is installed. Use the Drivers option to install the wave device." +MCIERR_WAVE_SETOUTPUTUNSUITABLE,"The device you are trying to play to cannot recognize the current file format." +MCIERR_WAVE_INPUTSUNSUITABLE, "No wave device that can record files in the current format is installed. Use the Drivers option to install the wave device." +MCIERR_WAVE_SETINPUTUNSUITABLE, "The device you are trying to record from cannot recognize the current file format." +MCIERR_NO_WINDOW, "There is no display window." +MCIERR_CREATEWINDOW, "Could not create or use window." +MCIERR_FILE_READ, "Cannot read the specified file. Make sure the file is still present, or check your disk or network connection." +MCIERR_FILE_WRITE, "Cannot write to the specified file. Make sure you have enough disk space or are still connected to the network." +MCIERR_SEQ_DIV_INCOMPATIBLE, "The time formats of the ""song pointer"" and SMPTE are mutually exclusive. You can't use them together." +MCIERR_SEQ_NOMIDIPRESENT, "The system has no installed MIDI devices. Use the Drivers option from the Control Panel to install a MIDI driver." +MCIERR_SEQ_PORT_INUSE, "The specified MIDI port is already in use. Wait until it is free; the try again." +MCIERR_SEQ_PORT_MAPNODEVICE, "The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use the MIDI Mapper option from the Control Panel to edit the setup." +MCIERR_SEQ_PORT_MISCERROR, "An error occurred with the specified port." +MCIERR_SEQ_PORT_NONEXISTENT, "The specified MIDI device is not installed on the system. Use the Drivers option from the Control Panel to install a MIDI device." +MCIERR_SEQ_PORTUNSPECIFIED, "The system doesn't have a current MIDI port specified." +MCIERR_SEQ_TIMER, "All multimedia timers are being used by other applications. Quit one of these applications; then, try again." + +END diff --git a/reactos/lib/winmm/winmm_Es.rc b/reactos/lib/winmm/winmm_Es.rc new file mode 100644 index 00000000000..29be5a6ad9a --- /dev/null +++ b/reactos/lib/winmm/winmm_Es.rc @@ -0,0 +1,126 @@ +/* + * Copyright 1999 Julio Cesar Gazquez + * + * 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 + */ + +STRINGTABLE LANGUAGE LANG_SPANISH, SUBLANG_DEFAULT + BEGIN + + /* MMSYS errors */ + MMSYSERR_NOERROR, "El comando especificado fue ejecutado." + MMSYSERR_ERROR, "Error externo indefinido." + MMSYSERR_BADDEVICEID, "Un identificador de dispositivo que ha sido usado estб fuera de rango para su sistema." + MMSYSERR_NOTENABLED, "El controlador no fue activado." + MMSYSERR_ALLOCATED, "El dispositivo especificado aъn estб en uso. Espere hasta que estй libre e intente nuevamente." + MMSYSERR_INVALHANDLE, "El handle de dispositivo especificado es invбlido." + MMSYSERR_NODRIVER, "No hay un controlador instalado en su sistema !\n" + MMSYSERR_NOMEM, "No hay suficiente memoria disponible para esta tarea. Cierre una o mбs aplicaciones para aumentar la memoria disponible e intente nuevamente." + MMSYSERR_NOTSUPPORTED, "Esta funciуn no estб soportada. Use la funciуn Capacidades para determinar que funciones y mensajes soporta el controlador." + MMSYSERR_BADERRNUM, "Se ha especificado un nъmero de error que no estб definido en el sistema." + MMSYSERR_INVALFLAG, "Se ha pasado un flag no vбlido a una funciуn del sistema." + MMSYSERR_INVALPARAM, "Se ha pasado un parбmetro no vбlido a una funciуn del sistema." + + /* WAVE errors */ + WAVERR_BADFORMAT, "El formato especificado no estб soportado o no puede ser traducido. Use la funciуn Capacidades para determinar los formatos soportados." + WAVERR_STILLPLAYING, "Esta operaciуn no puede ejecutarse mientras continъa la reproducciуn. Reinicie el dispositivo, o espere hasta que la reproducciуn termine." + WAVERR_UNPREPARED, "La cabecera del forma de onda no estб preparada. Use la funciуn Preparar para preparar la cabecera, e intente nuevamente." + WAVERR_SYNC, "No puede abrirse el dispositivo sin usar el flag WAVE_ALLOWSYNC. Use el flag, e intente nuevamente." + + /* MIDI errors */ + MIDIERR_UNPREPARED, "La cabecera MIDI no estб preparada. Use la funciуn Preparar para preparar la cabecera, e intente nuevamente." + MIDIERR_STILLPLAYING, "Esta operaciуn no puede ejecutarse mientras se continъa tocando. Reinicie el dispositivo, o espera hasta que termine de tocar." + MIDIERR_NOMAP, "No se encontrу un mapa MIDI. Puede haber un problema con el controlador, el el fichero MIDIMAP.CFG puede faltar o estar corrupto." + MIDIERR_NOTREADY, "El puerto estб transmitiendo datos al dispositivo. Espera hasta que los datos hayan sido transmitidos, e intente nuevamente." + MIDIERR_NODEVICE, "La configuraciуn actual del mapeador MIDI refiere a un dispositivo MIDI que no estб instalado en el sistema. Use el mapeador MIDI para editar la configuraciуn." + MIDIERR_INVALIDSETUP, "La configuraciуn actual de MIDI estб daсada. Copie el fichero MIDIMAP.CFG original al directorio SYSTEM de Windows SYSTEM, e intente nuevamente." + + /* MCI errors */ + MCIERR_INVALID_DEVICE_ID, "Identificador de dispositivo MCI invбlido. Use el identificador devuelto al abrir el dispositivo MCI." + MCIERR_UNRECOGNIZED_KEYWORD, "El controlador no puede reconocer el parбmetro de comando especificado." + MCIERR_UNRECOGNIZED_COMMAND, "El controlador no puede reconocer el comando especificado." + MCIERR_HARDWARE, "Hay un problema con su dispositivo. Asegъrese de que estй funcionando correctamente o contacte al fabricante del dispositivo." + MCIERR_INVALID_DEVICE_NAME, "El dispositivo especificado no estб abierto o no es reconocido por MCI." + MCIERR_OUT_OF_MEMORY, "No hay suficiente memoria para esta tarea.\nCierre una o mбs aplicaciones para aumentar la memoria disponible e intente nuevamente." + MCIERR_DEVICE_OPEN, "El nombre de dispositivo ya estб siendo usado como un alias por esta aplicaciуn. Use un alias ъnico." + MCIERR_CANNOT_LOAD_DRIVER, "Hay un problema no detectable en la carga del controlador de dispositivo especificado." + MCIERR_MISSING_COMMAND_STRING, "No se ha especificado un comando." + MCIERR_PARAM_OVERFLOW, "La cadena de salida es muy grande para caber en el buffer de retorno. Aumente el tamaсo del buffer." + MCIERR_MISSING_STRING_ARGUMENT, "El comando especificado requiere un parбmetro de cadena de caracteres. Por favor provea uno." + MCIERR_BAD_INTEGER, "El entero especificado es invбlido para este comando." + MCIERR_PARSER_INTERNAL, "El controlador de dispositivo devolviу un tipo de retorno invбlido. Contacte al fabricante del dispositivo para obtener un nuevo controlador." + MCIERR_DRIVER_INTERNAL, "Hay un problema con el controlador de dispositivo. Contacte al fabricante del dispositivo para obtener un nuevo controlador." + MCIERR_MISSING_PARAMETER, "El comando especificado requiere un parбmetro. Por favor provea uno." + MCIERR_UNSUPPORTED_FUNCTION, "El dispositivo MCI que estб usando no soporta el comando especificado." + MCIERR_FILE_NOT_FOUND, "No se encuentra el fichero especificado. Asegъrese que el path y el nombre del fichero son correctos." + MCIERR_DEVICE_NOT_READY, "El controlador de dispositivo no estб listo." + MCIERR_INTERNAL, "Un problema ha ocurrido inicializando el MCI. Intente reiniciar Windows." + MCIERR_DRIVER, "Hay un problema con el controlador del dispositivo. El controlador se ha cerrado. Intente reenviar el comando." + MCIERR_CANNOT_USE_ALL, "Utilice un nombre de dispositivo especнfico para este comando." + MCIERR_MULTIPLE, "Han ocurrido errores en mбs de un dispositivo. Especifique cada comando y dispositivo por separado para determinar que dispositivos causaron el error." + MCIERR_EXTENSION_NOT_FOUND, "No puede determinarse el tipo de dispositivo a partir de la extensiуn de fichero dada." + MCIERR_OUTOFRANGE, "El parбmetro especificado estб fuera del rango para el comando especificado." + MCIERR_FLAGS_NOT_COMPATIBLE, "Los parбmetros especificados no pueden usarse juntos." + MCIERR_FILE_NOT_SAVED, "No puede grabarse el fichero especificado. Asegъrese de tener suficiente espacio en disco o de que permanece conectado a la red." + MCIERR_DEVICE_TYPE_REQUIRED, "No puede encontrarse el dispositivo especificado. Asegъrese de que estб instalado o de que el nombre del dispositivo estб escrito correctamente." + MCIERR_DEVICE_LOCKED, "El dispositivo especificado estб siendo cerrado. Espere unos segundos e intente nuevamente." + MCIERR_DUPLICATE_ALIAS, "El alias especificado ya estб siendo usado por esta aplicaciуn. Use un alias ъnico." + MCIERR_BAD_CONSTANT, "El parбmetro especificado es invбlido para este comando." + MCIERR_MUST_USE_SHAREABLE, "El controlador de dispositivo ya estб en uso. Para compartirlo, use el parбmetro 'compartible' ('shareable') con cada comando 'abrir' ('open')." + MCIERR_MISSING_DEVICE_NAME, "El comando especificado requiere un alias, fichero, controlador o nombre de dispositivo. Por favor provea uno." + MCIERR_BAD_TIME_FORMAT, "El valor especificado para el formato de tiempo es invбlido. Verifique los formatos vбlidos en la documentaciуn de MCI." + MCIERR_NO_CLOSING_QUOTE, "Una comilla de cierre estб faltando en el valor del parбmetro. Por favor provea una." + MCIERR_DUPLICATE_FLAGS, "Un parбmetro o valor fue especificado dos veces. Especifнquelo una sola vez." + MCIERR_INVALID_FILE, "El fichero especificado no puede ser tocado en el dispositivo MCI especificado. El fichero puede estar corrupto o en un formato incorrecto." + MCIERR_NULL_PARAMETER_BLOCK, "Se ha pasado un bloque de parбmetros nulo al MCI." + MCIERR_UNNAMED_RESOURCE, "No puede guardarse un fichero sin nombre. Provea un nombre para el fichero." + MCIERR_NEW_REQUIRES_ALIAS, "Debe especificar un alias cuando utilice el parбmetro 'nuevo'." + MCIERR_NOTIFY_ON_AUTO_OPEN, "No puede usar el flag 'notificar' con dispositivos de apertura automбtica." + MCIERR_NO_ELEMENT_ALLOWED, "No puede usar un nombre de fichero con el dispositivo especificado." + MCIERR_NONAPPLICABLE_FUNCTION, "No pueden ejecutarse los comandos en el orden especificado. Corrija la secuencia de comandos e intente nuevamente." + MCIERR_ILLEGAL_FOR_AUTO_OPEN, "No puede ejecutarse el comando especificado en un dispositivo de apertura automбtica. Espere hasta que el dispositivo estй cerrado e intente nuevamente." + MCIERR_FILENAME_REQUIRED, "El nombre del fichero es invбlido. Asegъrese de que el nombre del fichero no es mayor de 8 caracteres, seguido por un punto y una extensiуn." + MCIERR_EXTRA_CHARACTERS, "No puede especificar caracteres extra despuйs de una cadena encerrada entre comillas." + MCIERR_DEVICE_NOT_INSTALLED, "El dispositivo especificado no estб instalado en el sistema. Use la opciуn Controladores en el Panel de Control para instalar el dispositivo." + MCIERR_GET_CD, "No puede accederse al fichero o dispositivo MCI especificado. Intente cambiando de directorio o reiniciando el equipo." + MCIERR_SET_CD, "No puede accederse al fichero o dispositivo MCI especificado porque la aplicaciуn no puede cambiar de directorio." + MCIERR_SET_DRIVE, "No puede accederse al fichero o dispositivo MCI especificado porque la aplicaciуn no puede cambiar de unidad." + MCIERR_DEVICE_LENGTH, "Especifique un dispositivo o nombre de controlador de menos de 79 caracteres." + MCIERR_DEVICE_ORD_LENGTH, "Especifique un dispositivo o nombre de controlador de menos de 69 caracteres." + MCIERR_NO_INTEGER, "El comando especificado requiere un parбmetro entero. Por favor provea uno." + MCIERR_WAVE_OUTPUTSINUSE, "Todos los dispositivos que pueden tocar ficheros en este formato estбn en uso. Espere hasta que se libere un dispositivo e intente nuevamente." + MCIERR_WAVE_SETOUTPUTINUSE, "No puede prepararse el dispositivo de forma de onda para reproducciуn porque estб en uso. Espere hasta que el dispositivo estй libre e intente nuevamente." + MCIERR_WAVE_INPUTSINUSE, "Todos los dispositivos que pueden grabar ficheros en este formato estбn en uso. Espere hasta que se libere un dispositivo e intente nuevamente." + MCIERR_WAVE_SETINPUTINUSE, "No puede prepararse el dispositivo de forma de onda para grabaciуn porque estб en uso. Espere hasta que el dispositivo estй libre e intente nuevamente." + MCIERR_WAVE_OUTPUTUNSPECIFIED, "Cualquier dispositivo compatible de reproducciуn de forma de onda puede ser usado." + MCIERR_WAVE_INPUTUNSPECIFIED, "Cualquier dispositivo compatible de grabaciуn de forma de onda puede ser usado." + MCIERR_WAVE_OUTPUTSUNSUITABLE, "No hay ningъn dispositivo de forma de onda instalado capaz de reproducir ficheros en este formato. Use la opciуn Dispositivos para instalar el dispositivo de forma de onda." + MCIERR_WAVE_SETOUTPUTUNSUITABLE,"El dispositivo con el que intenta reproducir no puede reconocer el formato de fichero." + MCIERR_WAVE_INPUTSUNSUITABLE, "No hay ningъn dispositivo de forma de onda instalado capaz de grabar ficheros en este formato. Use la opciуn Dispositivos para instalar el dispositivo de forma de onda." + MCIERR_WAVE_SETINPUTUNSUITABLE, "El dispositivo con el que intenta grabar no puede reconocer el formato de fichero." + MCIERR_NO_WINDOW, "No hay una ventana." + MCIERR_CREATEWINDOW, "No puede crearse o usar una ventana." + MCIERR_FILE_READ, "No puede leerse el fichero especificado. Asegъrese de que el fichero aъn estб presente, o revise su disco o conexiуn de red." + MCIERR_FILE_WRITE, "No puede grabarse el fichero especificado. Asegъrese de tener suficiente espacio en disco o de que permanece conectado a la red." + MCIERR_SEQ_DIV_INCOMPATIBLE, "Los formatos de tiempo de ""song pointer"" y SMPTE son mutuamente exclusivos. No pueden utilizarse a la vez." + MCIERR_SEQ_NOMIDIPRESENT, "El sistema no tiene dispositivos MIDI instalados. Use la opciуn Controladores en el Panel de Control para instalar el dispositivo." + MCIERR_SEQ_PORT_INUSE, "El puerto MIDI especificado ya estб en uso. Espere hasta que estй libre e intente nuevamente." + MCIERR_SEQ_PORT_MAPNODEVICE, "La configuraciуn actual del mapeador MIDI refiere a un dispositivo MIDI que no estб instalado en el sistema. Use el la opciуn del mapeador MIDI en el Panel de Control para editar la configuraciуn." + MCIERR_SEQ_PORT_MISCERROR, "Ha ocurrido un error con el puerto especificado." + MCIERR_SEQ_PORT_NONEXISTENT, "El dispositivo MIDI especificado no estб instalado en el sistema. Use la opciуn Dispositivos en el Panel de Control para instalar un dispositivo MIDI." + MCIERR_SEQ_PORTUNSPECIFIED, "El sistema no tiene actualmente un puerto MIDI especificado." + MCIERR_SEQ_TIMER, "Todos los temporizadores de multimedia estбn siendo usados por otras aplicaciones. Cierre una de esas aplicaciones e intente nuevamente." + + END diff --git a/reactos/lib/winmm/winmm_Fr.rc b/reactos/lib/winmm/winmm_Fr.rc new file mode 100644 index 00000000000..5da871383a2 --- /dev/null +++ b/reactos/lib/winmm/winmm_Fr.rc @@ -0,0 +1,131 @@ +/* + * Winmm + * French language support + * + * 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 + */ + +LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL + +STRINGTABLE +BEGIN + +/* MMSYS errors */ +MMSYSERR_NOERROR, "La commande spйcifiйe a йtй exйcutйe." +MMSYSERR_ERROR, "Erreur externe non dйfinie." +MMSYSERR_BADDEVICEID, "Un identificateur de pйriphйrique hors des limites pour votre systиme a йtй utilisй." +MMSYSERR_NOTENABLED, "Le pilote n'a pas йtй activй." +MMSYSERR_ALLOCATED, "Le pйriphйrique spйcifiй est en cours d'utilisation. Attendez qu'il soit libre, puis essayez а nouveau." +MMSYSERR_INVALHANDLE, "Le handle de pйriphйrique spйcifiй n'est pas valide." +MMSYSERR_NODRIVER, "Il n'y a pas de pilote installй sur votre systиme." +MMSYSERR_NOMEM, "Mйmoire insuffisante pour cette tвche. Quittez un ou plusieurs programmes, puis essayez а nouveau." +MMSYSERR_NOTSUPPORTED, "Fonction non prise en charge. Utilisez la fonction Capacitйs pour obtenir les fonctions de ce pilote." +MMSYSERR_BADERRNUM, "Un numйro d'erreur non dйfini dans le systиme a йtй spйcifiй." +MMSYSERR_INVALFLAG, "Un indicateur non valide a йtй transmis а une fonction systиme." +MMSYSERR_INVALPARAM, "Un paramиtre non valide a йtй passй а une fonction systиme." + +/* WAVE errors */ +WAVERR_BADFORMAT, "Le format choisi ne peut кtre traduit ou utilisй. Utilisez Capacitйs pour voir les formats pris en charge." +WAVERR_STILLPLAYING, "Le Lecteur multimйdia continue а lire des donnйes. Rйinitialisez-le ou attendez que toutes les donnйes aient йtй lues." +WAVERR_UNPREPARED, "L'en-tкte du son n'a pas йtй prйparй. Utilisez la fonction Prйparer pour le faire, puis essayez а nouveau." +WAVERR_SYNC, "Impossible d'ouvrir le pйriphйrique sans utiliser l'indicateur WAVE_ALLOWSYNC. Utilisez l'indicateur, puis essayez а nouveau." + +/* MIDI errors */ +MIDIERR_UNPREPARED, "L'en-tкte MIDI n'a pas йtй prйparй. Utilisez la fonction Prйparer pour le faire, puis essayez а nouveau." +MIDIERR_STILLPLAYING, "Le Lecteur multimйdia continue а lire des donnйes. Rйinitialisez-le ou attendez que toutes les donnйes aient йtй. lues." +MIDIERR_NOMAP, "Il n'y a pas d'instrument dйfini pour un mappeur MIDI. Utiliser l'onglet MIDI dans Propriйtйs multimйdia pour installer les instruments." +MIDIERR_NOTREADY, "Le port transmet des donnйes au pйriphйrique. Attendez la fin de la transmission, puis essayez а nouveau." +MIDIERR_NODEVICE, "Le fichier de description d'instrument MIDI (.IDF) n'est pas valide. Pour plus d'informations, contactez le constructeur de l'instrument." +MIDIERR_INVALIDSETUP, "Un appel MIDI non valide dans le mode d'ouverture en cours a йtй йmis. Ouvrez а nouveau le pйriphйrique en employant le mode correct." + +/* MCI errors */ +MCIERR_INVALID_DEVICE_ID, "ID de pйriphйrique MCI non valide. Utilisez l'ID renvoyй lorsque vous avez ouvert le pйriphйrique MCI." +MCIERR_UNRECOGNIZED_KEYWORD, "Le paramкtre de commande utilisй n'est pas dйfini dans l'ensemble de commandes MCI." +MCIERR_UNRECOGNIZED_COMMAND, "La commande utilisйe n'est pas une commande MCI valide." +MCIERR_HARDWARE, "Votre pйriphйrique multimйdia prйsente un problиme. Vйrifiez qu'il fonctionne convenablement ou contactez le constructeur." +MCIERR_INVALID_DEVICE_NAME, "Ce n'est pas un pйriphйrique MCI connu." +MCIERR_OUT_OF_MEMORY, "Mйmoire insuffisante pour cette tвche. Quittez un ou plusieurs programmes, puis essayez а nouveau." +MCIERR_DEVICE_OPEN, "Cet alias est dйjа utilisй par ce programme. Employez un alias unique plutфt que le nom du pйriphйrique." +MCIERR_CANNOT_LOAD_DRIVER, "Le pilote de pйriphйrique n'a pas pu кtre chargй. Vйrifiez qu'il est installй correctement." +MCIERR_MISSING_COMMAND_STRING, "La chaоne de commande est vide." +MCIERR_PARAM_OVERFLOW, "La chaоne de sortie йtait trop grande pour tenir dans la mйmoire tampon de retour. Augmentez la taille de la mйmoire tampon." +MCIERR_MISSING_STRING_ARGUMENT, "La commande spйcifiйe nйcessite un paramкtre chaоne de caractиres : veuillez l'entrer." +MCIERR_BAD_INTEGER, "Le nombre entier que vous avez spйcifiй n'est pas valide pour cette commande. Entrez un nombre." +MCIERR_PARSER_INTERNAL, "Le pilote de pйriphйrique a renvoyй une rйponse de type non valide. Pour obtenir un nouveau pilote, contactez le constructeur du pйriphйrique." +MCIERR_DRIVER_INTERNAL, "Le pilote de pйriphйrique prйsente un problиme. Demandez au constructeur du pйriphйrique de vous fournir un nouveau pilote." +MCIERR_MISSING_PARAMETER, "Il manque un paramкtre dans la commande spйcifiйe : veuillez l'entrer." +MCIERR_UNSUPPORTED_FUNCTION, "Le pйriphйrique MCI que vous utilisez ne prend pas en charge la commande spйcifiйe." +MCIERR_FILE_NOT_FOUND, "Le fichier spйcifiй est introuvable. Vйrifiez que le chemin d'accиs et le nom de fichier sont corrects." +MCIERR_DEVICE_NOT_READY, "Le pilote de pйriphйrique n'est pas prкt. Attendez une minute avant d'essayer а nouveau." +MCIERR_INTERNAL, "Un problиme est survenu lors de l'initialisation de MCI. Essayez de redйmarrer Windows." +MCIERR_DRIVER, "Une erreur spйcifique au pilote a provoquй sa fermeture. Essayez de relancer la commande." +MCIERR_CANNOT_USE_ALL, "Utilisez un nom de pйriphйrique spйcifique pour cette commande." +MCIERR_MULTIPLE, "Des erreurs se sont produites dans plusieurs pйriphйriques. Spйcifiez chaque commande et chaque pйriphйrique sйparйment afin de dйterminer les pйriphйriques qui ont provoquй les erreurs." +MCIERR_EXTENSION_NOT_FOUND, "Impossible de jouer ce fichier. Vйrifiez le nom de fichier ou installez un pilote qui reconnaоt ce type de fichier." +MCIERR_OUTOFRANGE, "Le paramкtre est hors limites pour la commande spйcifiйe." +MCIERR_FLAGS_NOT_COMPATIBLE, "Les paramкtres spйcifiйs ne peuvent кtre utilisйs ensemble." +MCIERR_FILE_NOT_SAVED, "Il est impossible d'enregistrer le fichier spйcifiй. Vйrifiez que vous avez assez d'espace disque ou que vous кtes toujours connectй au rйseau." +MCIERR_DEVICE_TYPE_REQUIRED, "Le pйriphйrique spйcifiй est introuvable. Vйrifiez s'il est installй ou si son nom est correctement orthographiй." +MCIERR_DEVICE_LOCKED, "Le pйriphйrique spйcifiй est en cours de fermeture. Attendez quelques secondes, puis essayez а nouveau." +MCIERR_DUPLICATE_ALIAS, "L'alias spйcifiй est dйjа utilisй dans cette application. Utilisez un alias unique." +MCIERR_BAD_CONSTANT, "La constante utilisйe n'est pas correcte pour cette commande." +MCIERR_MUST_USE_SHAREABLE, "Le pilote de pйriphйrique est dйjа utilisй en ce moment. Pour le partager, utilisez le paramкtre de partage ('shareable') dans chaque commande d'ouverture ('open')." +MCIERR_MISSING_DEVICE_NAME, "La commande spйcifiйe requiert un nom d'alias, de fichier, de pilote ou de pйriphйrique : veuillez l'entrer." +MCIERR_BAD_TIME_FORMAT, "La valeur spйcifiйe comme format horaire n'est pas valide. Les formats valides sont indiquйs dans la documentation MCI." +MCIERR_NO_CLOSING_QUOTE, "Un guillemet double fermant manque dans la valeur du paramкtre. Ajoutez-le." +MCIERR_DUPLICATE_FLAGS, "Un paramкtre ou une valeur a йtй spйcifiй deux fois et ne doit кtre spйcifiй qu'une seule fois." +MCIERR_INVALID_FILE, "Le fichier ne peut pas кtre exйcutй sur un pйriphйrique MCI spйcifiй. Le fichier est endommagй ou son format n'est pas correct." +MCIERR_NULL_PARAMETER_BLOCK, "Un bloc de paramкtres nuls a йtй passй а MCI." +MCIERR_UNNAMED_RESOURCE, "Impossible d'enregistrer un fichier sans nom. Entrez un nom de fichier." +MCIERR_NEW_REQUIRES_ALIAS, "Vous devez spйcifier un alias lorsque vous employez le paramкtre 'nouveau'." +MCIERR_NOTIFY_ON_AUTO_OPEN, "Il est impossible d'utiliser l'indicateur 'notifier' avec les pйriphйriques а ouverture automatique." +MCIERR_NO_ELEMENT_ALLOWED, "Impossible d'utiliser un nom de fichier avec le pйriphйrique spйcifiй." +MCIERR_NONAPPLICABLE_FUNCTION, "Impossible d'exйcuter les commandes dans l'ordre spйcifiй. Corrigez l'ordre des commandes, puis essayez а nouveau." +MCIERR_ILLEGAL_FOR_AUTO_OPEN, "Impossible d'exйcuter cette commande sur un pйriphйrique а ouverture automatique. Attendez que le pйriphйrique soit fermй pour essayer а nouveau." +MCIERR_FILENAME_REQUIRED, "Le nom de fichier est incorrect." +MCIERR_EXTRA_CHARACTERS, "Il est impossible de spйcifier des caractиres supplйmentaires aprиs une chaоne placйe entre guillemets." +MCIERR_DEVICE_NOT_INSTALLED, "Ce pйriphйrique n'est pas installй. Pour installer un nouveau pilote, double-cliquez sur l'icфne Ajout de pйriphйrique dans le Panneau de configuration." +MCIERR_GET_CD, "Impossible d'accйder au fichier ou au pйriphйrique MCI spйcifiй. Essayez de changer de rйpertoire ou de redйmarrer votre ordinateur." +MCIERR_SET_CD, "Impossible d'accйder au fichier ou au pйriphйrique MCI spйcifiй, car l'application ne peut pas changer de rйpertoire." +MCIERR_SET_DRIVE, "Impossible d'accйder au fichier ou au pйriphйrique MCI spйcifiй, car l'application ne peut pas changer de lecteur." +MCIERR_DEVICE_LENGTH, "Spйcifiez un nom de pйriphйrique ou de pilote de moins de 79 caractиres." +MCIERR_DEVICE_ORD_LENGTH, "Spйcifiez un nom de pйriphйrique ou de pilote comptant moins de 69 caractиres." +MCIERR_NO_INTEGER, "La commande spйcifiйe nйcessite un paramкtre numйrique. Exemple : ""jouer jusqu'а 10"". Entrez ce paramкtre." +MCIERR_WAVE_OUTPUTSINUSE, "Tous les pйriphйriques audio capables de jouer des fichiers sous ce format sont en cours d'utilisation. Attendez qu'un pйriphйrique audio soit libre, puis essayez а nouveau." +MCIERR_WAVE_SETOUTPUTINUSE, "Le pйriphйrique audio de lecture est en cours d'utilisation. Attendez qu'il soit libre, puis essayez а nouveau." +MCIERR_WAVE_INPUTSINUSE, "Tous les pйriphйriques audio capables d'enregistrer des fichiers sous ce format sont en cours d'utilisation. Attendez qu'un pйriphйrique audio soit libre, puis essayez а nouveau." +MCIERR_WAVE_SETINPUTINUSE, "Le pйriphйrique audio d'enregistrement est en cours d'utilisation. Attendez qu'il soit libre, puis essayez а nouveau." +MCIERR_WAVE_OUTPUTUNSPECIFIED, "N'importe quel pйriphйrique audio de lecture peut кtre utilisй." +MCIERR_WAVE_INPUTUNSPECIFIED, "N'importe quel pйriphйrique audio d'enregistrement peut кtre utilisй." +MCIERR_WAVE_OUTPUTSUNSUITABLE, "Aucun pйriphйrique audio capable de jouer des fichiers sous le format en cours n'a йtй installй." +MCIERR_WAVE_SETOUTPUTUNSUITABLE,"Ce pйriphйrique ne parvient pas а reconnaоtre le format du fichier actuel. Sйlectionnez un autre pйriphйrique, puis essayez а nouveau." +MCIERR_WAVE_INPUTSUNSUITABLE, "Aucun pйriphйrique audio capable d'enregistrer des fichiers sous le format en cours n'a йtй installй." +MCIERR_WAVE_SETINPUTUNSUITABLE, "Ce pйriphйrique ne parvient pas а reconnaоtre le format du fichier actuel. Sйlectionnez un autre pйriphйrique, puis essayez а nouveau." +MCIERR_NO_WINDOW, "Il n'y pas de fenкtre d'affichage." +MCIERR_CREATEWINDOW, "Impossible d'utiliser ou de crйer une fenкtre." +MCIERR_FILE_READ, "Impossible de lire ce fichier. Assurez-vous qu'il n'a pas йtй supprimй ou vйrifiez votre disque ou votre connexion rйseau." +MCIERR_FILE_WRITE, "Il est impossible d'йcrire des informations dans le fichier spйcifiй. Vйrifiez que vous avez assez d'espace disque ou que vous кtes toujours connectй au rйseau." +MCIERR_SEQ_DIV_INCOMPATIBLE, "Il est impossible d'utiliser le format horaire pointeur de piste et le format horaire SMPTE en mкme temps." +MCIERR_SEQ_NOMIDIPRESENT, "Le systиme n'a pas de pйriphйriques MIDI installйs. Pour installer un nouveau pilote, double-cliquez sur l'icфne Ajout de pйriphйrique dans le Panneau de configuration." +MCIERR_SEQ_PORT_INUSE, "Le port MIDI spйcifiй est dйjа utilisй. Attendez qu'il soit libre et essayez а nouveau." +MCIERR_SEQ_PORT_MAPNODEVICE, "La configuration actuelle du mappeur MIDI fait rйfйrence а un pйriphйrique MIDI non installй sur votre systиme. Utilisez l'option mappeur MIDI dans le Control Panel pour changer la configuration." +MCIERR_SEQ_PORT_MISCERROR, "Une erreur est survenue sur le port spйcifiй." +MCIERR_SEQ_PORT_NONEXISTENT, "Ce pйriphйrique n'est pas installй. Pour installer un nouveau pilote, double-cliquez sur l'icфne Ajout de pйriphйrique dans le Panneau de configuration." +MCIERR_SEQ_PORTUNSPECIFIED, "Le systиme n'a pas spйcifiй de port MIDI par dйfaut." +MCIERR_SEQ_TIMER, "Tous les timers multimйdia sont en cours d'utilisation par d'autres applications. Quittez une de ces applications et essayez а nouveau." + +END diff --git a/reactos/lib/winmm/winmm_It.rc b/reactos/lib/winmm/winmm_It.rc new file mode 100644 index 00000000000..52de5f0af67 --- /dev/null +++ b/reactos/lib/winmm/winmm_It.rc @@ -0,0 +1,127 @@ +/* + * Copyright 1999 Eric Pouech + * Copyright 2003 Ivan Leo Puoti + * + * 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 + */ + +STRINGTABLE LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL +BEGIN + +/* MMSYS errors */ +MMSYSERR_NOERROR, "Il comando specificato и stato eseguito." +MMSYSERR_ERROR, "Errore esterno sconosciuto." +MMSYSERR_BADDEVICEID, "E' stato usato l'ID di un dispositivo che и fuori dalla portata del sistema." +MMSYSERR_NOTENABLED, "Il driver non и abilitato." +MMSYSERR_ALLOCATED, "Il driver specificato и giа in uso. Attendere che sia nuovamente disponibile, e riprovare." +MMSYSERR_INVALHANDLE, "Il handle del dispositivo specificato и invalido." +MMSYSERR_NODRIVER, "Non и installato nessun driver nel sistema !\n" +MMSYSERR_NOMEM, "Memoria insufficente per eseguire questa operazione. Chiudere una o piщ applicazioni per aumentare la memoria disponibile, e riprovare." +MMSYSERR_NOTSUPPORTED, "Questa funzione non и supportata. Usare la funzione Capabilities per determinare quali funzioni e messaggi sono supportati dal driver." +MMSYSERR_BADERRNUM, "E' stato specificato un numero di errore non definito dal sistema." +MMSYSERR_INVALFLAG, "Un flag invalido и stato passato a una funzione di sistema." +MMSYSERR_INVALPARAM, "Un parametro invalido и stato pasato a una funzione di sistema." + +/* WAVE errors */ +WAVERR_BADFORMAT, "Il formato specificato non и supportato o non puт essere tradotto. Usare la funzione Capabilities per determinare le funzioni supportate" +WAVERR_STILLPLAYING, "Non и possibile effetuare questa operazione durante l'esecuzione. Reinizializzare il dispositivo, o attendere la fine dell'esecuzione." +WAVERR_UNPREPARED, "Il header wave non и stato preparato. Usare la funzione Prepare per preparale l'header, e riprovare." +WAVERR_SYNC, "Non и possibile aprire il dispositivo senza usare il flag WAVE_ALLOWSYNC. Usare il flag, e riprovare." + +/* MIDI errors */ +MIDIERR_UNPREPARED, "L'header MIDI non и stato preparato. Usare la funzione Prepare per preparare l'header, e riprovare." +MIDIERR_STILLPLAYING, "Non и possibile effetuare questa operazione durante l'esecuzione. Reinizializzare il dispositivo, o attendere la fine dell'esecuzione." +MIDIERR_NOMAP, "Non и stata trovata una mappa MIDI. Ci potrebbe essere un problema con il driver, o il file MIDIMAP.CFG potrebbe essere danneggiato o mancante." +MIDIERR_NOTREADY, "La porta sta trasmettendo dei dati al dispositivo. Attendere la trasmissione di tutti i dati, e riprovare." +MIDIERR_NODEVICE, "La configurazione attuale del Mapper MIDI si riferisce a un dispositivo MIDI che non и presente nel sistema. Usare il Mapper MIDI per modificare la configurazione." +MIDIERR_INVALIDSETUP, "La configutazione MIDI attuale и danneggiata. Copiare il file MIDIMAP.CFG nella directory SYSTEM di Windows, e riprovare." + +/* MCI errors */ +MCIERR_INVALID_DEVICE_ID, "ID del dispositivo MCI invalido. Usare l'ID restituito quando si и aperto il dispositivo MCI." +MCIERR_UNRECOGNIZED_KEYWORD, "Il driver non riconosce il parametro del comando specificato." +MCIERR_UNRECOGNIZED_COMMAND, "Il driver non riconosce il comando specificato." +MCIERR_HARDWARE, "C'и un problema con il dispositivo multimediale. Controllare che il funzionamento del dispositivo o contattare il produttore." +MCIERR_INVALID_DEVICE_NAME, "Il dispositivo specificato non и aperto o non и supportato da MCI." +MCIERR_OUT_OF_MEMORY, "Memoria insufficente per eseguire questa operazione. \nChiudere una o piщ applicazioni per aumentare la memoria disponibile, e riprovare." +MCIERR_DEVICE_OPEN, "Il nome del dispositivo и giа in uso come alias da parte di questa applicazione. Usare un alias univoco." +MCIERR_CANNOT_LOAD_DRIVER, "Si и verificato un problema non rilevabile nel caricamento del driver specificato." +MCIERR_MISSING_COMMAND_STRING, "Non и stato specificato nessun comando." +MCIERR_PARAM_OVERFLOW, "La stringa di output и troppo grande per entrare nel buffer di ritorno. Aumentare la dimensione del buffer." +MCIERR_MISSING_STRING_ARGUMENT, "Il comando specificato richiede un parametro che sia una stringa di caratteri. Fornirne uno." +MCIERR_BAD_INTEGER, "Il numero intreo specificato non и valido per questo comando." +MCIERR_PARSER_INTERNAL, "Il driver ha restituito un tipo non valido. Contattare il produttore del dispositivo per ottenere un nuovo driver." +MCIERR_DRIVER_INTERNAL, "C'и un problema con il driver. Contattare il produttore del dispositivo per ottenere un nuovo driver." +MCIERR_MISSING_PARAMETER, "Il comando specificato richiede un parametro. Fornirne uno." +MCIERR_UNSUPPORTED_FUNCTION, "Il dispositivo MCI in uso non supporta il comando specificato." +MCIERR_FILE_NOT_FOUND, "Il file specificato non и stato trovato. Controllare che l'indirizzo e il nome del file siano corretti." +MCIERR_DEVICE_NOT_READY, "Il driver non и pronto." +MCIERR_INTERNAL, "Si и verificato un problema nell'inizializazione di MCI. Provare a riavviare Windows." +MCIERR_DRIVER, "Si и verificato un errore nel driver. Il driver и stato chiuso. Errore non accessibile." +MCIERR_CANNOT_USE_ALL, "Non и possibile usare 'all' come nome del dispositivo con il comando specificato." +MCIERR_MULTIPLE, "Si sono verificati degli errori in piщ di un dispositivo. Specificare ogni comando e dispositivo separatamente per determinare quale dispositivo ha causato l'errore" +MCIERR_EXTENSION_NOT_FOUND, "Impossibile determinare il tipo di dispositivo dall'estensione data." +MCIERR_OUTOFRANGE, "Il parametro specificato и fuori dalla portata del comando specificato." +MCIERR_FLAGS_NOT_COMPATIBLE, "I parametri specificati non possono essere usati insieme." +MCIERR_FILE_NOT_SAVED, "Impossibile salvare il file specificato. Controllare di avere abbastanza spazio libero e di essere ancora connessi alla rete." +MCIERR_DEVICE_TYPE_REQUIRED, "Impossibile trovare il dispositivo specificato. Controllare che sia installato e che il nome sia digitato correttamente." +MCIERR_DEVICE_LOCKED, "Il dispositivo specificato verrа chiuso. Attendere alcuni secondi e riprovare." +MCIERR_DUPLICATE_ALIAS, "L'alias specificato и giа in uso da parte di questa applicazione. Usare un alias univoco." +MCIERR_BAD_CONSTANT, "Il parametro specificato и invalido per questo comando." +MCIERR_MUST_USE_SHAREABLE, "Il driver и giа in uso. Per condividerlo, usare il parametro 'shareable' con ogni comando 'open'." +MCIERR_MISSING_DEVICE_NAME, "Il comando specificato richiede un alias, un file, un driver o il nome di un dispositivo. Fornirne uno." +MCIERR_BAD_TIME_FORMAT, "Il valore specificato и invalido per il formato dell'orario. Consultare la documentazione dell'MCI per i formati validi." +MCIERR_NO_CLOSING_QUOTE, "Manca una doppia vorgoletta di chiusura dal valore del parametro. Fornirne una." +MCIERR_DUPLICATE_FLAGS, "Un valore o parametro и stato specificato due volte. Specificarlo solo una volta." +MCIERR_INVALID_FILE, "Il file specificato non puт essere aperto con il dispositivo MCI specificato. Il file potrebbe essere daneggiato, o in un formato errato." +MCIERR_NULL_PARAMETER_BLOCK, "Un null parameter block и stato passato a MCI." +MCIERR_UNNAMED_RESOURCE, "Non и possibile salvare un file senza nome. Fornire un nome al file." +MCIERR_NEW_REQUIRES_ALIAS, "E' necessario specificare un alias quando si usa il parametro 'new'." +MCIERR_NOTIFY_ON_AUTO_OPEN, "Non и possibile usare il flag 'notify' con dispositivi auto-aperti." +MCIERR_NO_ELEMENT_ALLOWED, "Non и possibile usare un nome file con il dispositivo specificato." +MCIERR_NONAPPLICABLE_FUNCTION, "Non и possibile eseguire i comandi nell'ordine specificato. Correggere la sequenza, e riprovare." +MCIERR_ILLEGAL_FOR_AUTO_OPEN, "Non и possibile eseguire il comando specificato con un dispositivo auto-aperto. Attendere che il dispositivo si sia chiuso, e riprovare." +MCIERR_FILENAME_REQUIRED, "Il nome del file и invalido. Controllare che il nome del file non sia piщ lungo di 8 caratteri, seguito da un periodo e un'estensione." +MCIERR_EXTRA_CHARACTERS, "Non и possibile specificare altri caratteri dopo una stringa compresa tra virgolette." +MCIERR_DEVICE_NOT_INSTALLED, "Il dispositivo specificato non и installato nel sistema. Usare l'opzione Drivers nel Pannello di Controllo per installare il dispositivo." +MCIERR_GET_CD, "Impossibile accedere al file o dispositivo MCI specificato. Provare a cambiare directory o riavviare il computer." +MCIERR_SET_CD, "Impossibile accedere al file o dispositivo MCI specificato perchи l'applicazione non puт cambiare directory." +MCIERR_SET_DRIVE, "Impossibile accedere al file o dispositivo MCI specificato perchи l'applicazione non puт cambiare drive." +MCIERR_DEVICE_LENGTH, "Specificare un driver o dispositivo con meno di 79 caratteri." +MCIERR_DEVICE_ORD_LENGTH, "Specificare un driver o dispositivo con meno di 69 caratteri." +MCIERR_NO_INTEGER, "Il comando specificato richiede un numero intero come parametro. Fornirne uno." +MCIERR_WAVE_OUTPUTSINUSE, "Tutti i dispositivi wave che possono leggere il file nel formato attuale sono in uso. Attendere che un dispositivo wave sia libero, e riprovare." +MCIERR_WAVE_SETOUTPUTINUSE, "Non и possibile impostare il dispositivo wave attuale per il play back perchи и in uso. Attendere che il dispositivo sia libero, e riprovare." +MCIERR_WAVE_INPUTSINUSE, "Tutti i dispositivi wave che possono registrare nel formato attuale sono in uso. Attendere che un dispositivo wave sia disponibile, e riprovare." +MCIERR_WAVE_SETINPUTINUSE, "Non и possibile impostare il dispositivo per registrare perchи и in uso. Attendere che il dispositivo sia disponibile, e riprovare." +MCIERR_WAVE_OUTPUTUNSPECIFIED, "Puт essere usato qualunque dispositivo compatibile waveform per il playback." +MCIERR_WAVE_INPUTUNSPECIFIED, "Puт essere usato qualunque dispositivo compatibile waveform per registrare." +MCIERR_WAVE_OUTPUTSUNSUITABLE, "Nessun dispositivo wave installato puт leggere i file nel formato attuale. Usare l'opzione drivers per installare un dispositivo wave." +MCIERR_WAVE_SETOUTPUTUNSUITABLE,"Il dispositivo che si sta usando per leggere il file non risonosce il formato del file attuale." +MCIERR_WAVE_INPUTSUNSUITABLE, "Non и installato nessun dipositivo wave che possa registrare dei file nel formato attuale. Usare l'opzione Drivers per installare un dispositivo wave." +MCIERR_WAVE_SETINPUTUNSUITABLE, "Il dispositivo che si sta usando per registrare non risonosce il formato attuale." +MCIERR_NO_WINDOW, "Non c'и nessuna finestra di visualizzazione." +MCIERR_CREATEWINDOW, "Impossibile usare o creare la finestra." +MCIERR_FILE_READ, "Impossibile leggere il file specificato. Assicurarsi che il file sia ancora presente, o controllare il disco o la connessione di rete." +MCIERR_FILE_WRITE, "Impossibile scrivere il file specificato. Controllare di avere spazio libero sufficente sul disco o di essere ancora connessi alla rete." +MCIERR_SEQ_DIV_INCOMPATIBLE, "I formati dell'orario del ""song pointer"" e SMPTE si escludono vicendevolmente. Non si possono usare insieme." +MCIERR_SEQ_NOMIDIPRESENT, "Nel sistema non sono installati dispositivi MIDI. Usare l'opzione Drivers dal Pannello di Controllo per installare un driver MIDI." +MCIERR_SEQ_PORT_INUSE, "La porta MIDI specificata и giа in uso. Attendere che sia libera, e riprovare." +MCIERR_SEQ_PORT_MAPNODEVICE, "La configurazione del Mapper MIDI si riferisce a un dispositivo MIDI che non и installato nel sistema. Usare l'opzione Mapper MIDI nel Pannello di Controllo per cambiare la configurazione." +MCIERR_SEQ_PORT_MISCERROR, "Si и verificato un errore con la porta specificata." +MCIERR_SEQ_PORT_NONEXISTENT, "Il dispositivo MIDI specificato non и installato nel sistema. Usare l'opzione DRIVERS nel Pannello di Controllo per installare un dispositivo MIDI." +MCIERR_SEQ_PORTUNSPECIFIED, "Non и stata specificata una porta MIDI nel sistema." +MCIERR_SEQ_TIMER, "Tutti i timer multimediali sono in uso da parte di altre applicazioni. Chiudere una di questa applicazioni, e riprovare." + +END diff --git a/reactos/lib/winmm/winmm_Ja.rc b/reactos/lib/winmm/winmm_Ja.rc new file mode 100644 index 00000000000..130b0d95384 --- /dev/null +++ b/reactos/lib/winmm/winmm_Ja.rc @@ -0,0 +1,126 @@ +/* + * Copyright 2004 Hajime Segawa + * + * 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 + */ + +STRINGTABLE LANGUAGE LANG_JAPANESE, SUBLANG_NEUTRAL +BEGIN + +/* MMSYS errors */ +MMSYSERR_NOERROR, "Ћw’и‚і‚к‚ЅѓRѓ}ѓ“ѓh‚рЋАЌs‚Е‚«‚Ь‚№‚с‚Е‚µ‚ЅЃB" +MMSYSERR_ERROR, "•s–ѕ‚ИЉO•”ѓGѓ‰Ѓ[‚Е‚·ЃB" +MMSYSERR_BADDEVICEID, "–іЊш‚ИѓfѓoѓCѓXID‚Е‚·ЃB" +MMSYSERR_NOTENABLED, "ѓhѓ‰ѓCѓo‚Є—LЊш‚Й‚И‚Б‚Д‚ў‚Ь‚№‚сЃB" +MMSYSERR_ALLOCATED, "Ћw’и‚і‚к‚ЅѓfѓoѓCѓX‚НЋg—p’†‚Е‚·ЃBѓfѓoѓCѓX‚Є‰р•ъ‚і‚к‚й‚Ь‚Е‘Т‚Б‚Д‚©‚з‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" +MMSYSERR_INVALHANDLE, "–іЊш‚ИѓfѓoѓCѓXѓnѓ“ѓhѓ‹‚Е‚·ЃB" +MMSYSERR_NODRIVER, "ѓVѓXѓeѓЂ‚Йѓhѓ‰ѓCѓo‚ЄѓCѓ“ѓXѓgЃ[ѓ‹‚і‚к‚Д‚ў‚Ь‚№‚с!\n" +MMSYSERR_NOMEM, "‚±‚М‘ЂЌм‚рЋАЌs‚·‚й‚Ѕ‚Я‚МѓЃѓ‚ѓЉ‚Є•s‘«‚µ‚Д‚ў‚Ь‚·ЃB‚ў‚­‚В‚©‚МѓAѓvѓЉѓPЃ[ѓVѓ‡ѓ“‚рЏI—№‚µ‚Д‹у‚«ѓЃѓ‚ѓЉ‚р‘ќ‚в‚µ‚Д‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" +MMSYSERR_NOTSUPPORTED, "‚±‚М‹@”\‚НѓTѓ|Ѓ[ѓg‚і‚к‚Д‚ў‚Ь‚№‚сЃBCapabilitiesЉЦђ”‚рЋg—p‚µ‚Дѓhѓ‰ѓCѓo‚ЄѓTѓ|Ѓ[ѓg‚·‚й‹@”\‚ЖѓЃѓbѓZЃ[ѓW‚рЉm”F‚µ‚Д‰є‚і‚ўЃB" +MMSYSERR_BADERRNUM, "Ћw’и‚і‚к‚ЅѓGѓ‰Ѓ[”ФЌ†‚Н’и‹`‚і‚к‚Д‚ў‚Ь‚№‚сЃB" +MMSYSERR_INVALFLAG, "ѓVѓXѓeѓЂЉЦђ”‚Й–іЊш‚Иѓtѓ‰ѓO‚Є“n‚і‚к‚Ь‚µ‚ЅЃB" +MMSYSERR_INVALPARAM, "ѓVѓXѓeѓЂЉЦђ”‚Й–іЊш‚Иѓpѓ‰ѓЃЃ[ѓ^‚Є“n‚і‚к‚Ь‚µ‚ЅЃB" + +/* WAVE errors */ +WAVERR_BADFORMAT, "Ћw’и‚і‚к‚ЅѓtѓHЃ[ѓ}ѓbѓg‚НѓTѓ|Ѓ[ѓg‚і‚к‚Д‚ў‚И‚ў‚©ЃA‰рЋЯ‚Е‚«‚Ь‚№‚сЃBCapabilitiesЉЦђ”‚рЋg—p‚µ‚ДѓTѓ|Ѓ[ѓg‚і‚к‚Д‚ў‚йѓtѓHЃ[ѓ}ѓbѓg‚рЉm”F‚µ‚Д‰є‚і‚ўЃB" +WAVERR_STILLPLAYING, "ѓЃѓfѓBѓAЌДђ¶’†‚Й‚Н‚±‚М‘ЂЌм‚рЋАЌs‚Е‚«‚Ь‚№‚сЃBѓfѓoѓCѓX‚рѓЉѓZѓbѓg‚·‚й‚©ЌДђ¶‚ЄЏI‚н‚й‚Ь‚Е‘Т‚Б‚Д‰є‚і‚ўЃB" +WAVERR_UNPREPARED, "waveѓwѓbѓ_‚ЄЏЂ”х‚і‚к‚Д‚ў‚Ь‚№‚сЃBPrepareЉЦђ”‚рЋg—p‚µ‚Дѓwѓbѓ_‚рЏЂ”х‚µ‚Д‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" +WAVERR_SYNC, "WAVE_ALLOWSYNCѓtѓ‰ѓO‚И‚µ‚Е‚НѓfѓoѓCѓX‚рѓIЃ[ѓvѓ“‚Е‚«‚Ь‚№‚сЃBѓtѓ‰ѓO‚рЋw’и‚µ‚Д‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" + +/* MIDI errors */ +MIDIERR_UNPREPARED, "MIDIѓwѓbѓ_‚ЄЏЂ”х‚і‚к‚Д‚ў‚Ь‚№‚сЃBPrepareЉЦђ”‚рЋg—p‚µ‚Дѓwѓbѓ_‚рЏЂ”х‚µ‚Д‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" +MIDIERR_STILLPLAYING, "ѓЃѓfѓBѓAЌДђ¶’†‚Й‚Н‚±‚М‘ЂЌм‚рЋАЌs‚Е‚«‚Ь‚№‚сЃBѓfѓoѓCѓX‚рѓЉѓZѓbѓg‚·‚й‚©ЌДђ¶‚ЄЏI‚н‚й‚Ь‚Е‘Т‚Б‚Д‰є‚і‚ўЃB" +MIDIERR_NOMAP, "MIDIѓ}ѓbѓv‚ЄЊ©‚В‚©‚и‚Ь‚№‚сЃBѓhѓ‰ѓCѓo‚М–в‘и‚©ЃAMIDIMAP.CFGѓtѓ@ѓCѓ‹‚Є”j‘№‚µ‚Д‚ў‚й‚©‘¶ЌЭ‚µ‚И‚ў‰В”\ђ«‚Є‚ ‚и‚Ь‚·ЃB" +MIDIERR_NOTREADY, "ѓ|Ѓ[ѓg‚НѓfѓoѓCѓX‚ЙѓfЃ[ѓ^‚р‘—ђM’†‚Е‚·ЃBѓfЃ[ѓ^‚М‘—ђM‚ЄЏI‚н‚й‚Ь‚Е‘Т‚Б‚Д‚©‚з‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" +MIDIERR_NODEVICE, "MIDIѓ}ѓbѓp‚МђЭ’и‚ЄѓVѓXѓeѓЂ‚Й‘•’…‚і‚к‚Д‚ў‚И‚ўѓfѓoѓCѓX‚рЋQЏЖ‚µ‚Д‚ў‚Ь‚·ЃBђЭ’и‚р•ПЌX‚·‚й‚Й‚НѓRѓ“ѓgѓЌЃ[ѓ‹ѓpѓlѓ‹‚МЃuMIDIѓ}ѓbѓpЃvѓAѓvѓЊѓbѓg‚рЋg—p‚µ‚Д‰є‚і‚ўЃB" +MIDIERR_INVALIDSETUP, "MIDI‚МђЭ’и‚Є”j‘№‚µ‚Д‚ў‚Ь‚·ЃBѓIѓЉѓWѓiѓ‹‚МMIDIMAP.CFGѓtѓ@ѓCѓ‹‚рWindows‚МSYSTEMѓfѓBѓЊѓNѓgѓЉ‚©‚зѓRѓsЃ[‚µ‚Д‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" + +/* MCI errors */ +MCIERR_INVALID_DEVICE_ID, "–іЊш‚ИMCIѓfѓoѓCѓXID‚Е‚·ЃBMCIѓfѓoѓCѓX‚рѓIЃ[ѓvѓ“‚µ‚Ѕ‚Ж‚«‚Й•Ф‚і‚к‚ЅID‚рЋg—p‚µ‚Д‰є‚і‚ўЃB" +MCIERR_UNRECOGNIZED_KEYWORD, "ѓhѓ‰ѓCѓo‚НЋw’и‚і‚к‚ЅѓRѓ}ѓ“ѓh‚Мѓpѓ‰ѓЃЃ[ѓ^‚р”FЋЇ‚Е‚«‚Ь‚№‚с‚Е‚µ‚ЅЃB" +MCIERR_UNRECOGNIZED_COMMAND, "ѓhѓ‰ѓCѓo‚НЋw’и‚і‚к‚ЅѓRѓ}ѓ“ѓh‚р”FЋЇ‚Е‚«‚Ь‚№‚с‚Е‚µ‚ЅЃB" +MCIERR_HARDWARE, "ѓЃѓfѓBѓAѓfѓoѓCѓX‚Й–в‘и‚Є”­ђ¶‚µ‚Ь‚µ‚ЅЃBѓfѓoѓCѓX‚ЄђіЏн‚Й“®Ќм‚µ‚Д‚ў‚й‚©Љm”F‚·‚й‚©ЃAђ»‘ўЊі‚Й–в‚ўЌ‡‚н‚№‚Д‰є‚і‚ўЃB" +MCIERR_INVALID_DEVICE_NAME, "Ћw’и‚і‚к‚ЅѓfѓoѓCѓX‚НѓIЃ[ѓvѓ“‚і‚к‚Д‚ў‚И‚ў‚©ЃAMCI‚Й”FЋЇ‚і‚к‚Д‚ў‚Ь‚№‚сЃB" +MCIERR_OUT_OF_MEMORY, "‚±‚М‘ЂЌм‚рЋАЌs‚·‚й‚Ѕ‚Я‚МѓЃѓ‚ѓЉ‚Є•s‘«‚µ‚Д‚ў‚Ь‚·ЃB\n‚ў‚­‚В‚©‚МѓAѓvѓЉѓPЃ[ѓVѓ‡ѓ“‚рЏI—№‚µ‚Д‹у‚«ѓЃѓ‚ѓЉ‚р‘ќ‚в‚µ‚Д‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" +MCIERR_DEVICE_OPEN, "ѓfѓoѓCѓX–ј‚Н‚±‚МѓAѓvѓЉѓPЃ[ѓVѓ‡ѓ“‚Й‚ж‚Б‚ДѓGѓCѓЉѓAѓX‚Ж‚µ‚ДЋg—p‚і‚к‚Д‚ў‚Ь‚·ЃB“ЖЋ©‚МѓGѓCѓЉѓAѓX‚рЋg—p‚µ‚Д‰є‚і‚ўЃB" +MCIERR_CANNOT_LOAD_DRIVER, "Ћw’и‚і‚к‚ЅѓfѓoѓCѓXѓhѓ‰ѓCѓo‚МѓЌЃ[ѓh’†‚Й•s–ѕ‚ИѓGѓ‰Ѓ[‚Є”­ђ¶‚µ‚Ь‚µ‚ЅЃB" +MCIERR_MISSING_COMMAND_STRING, "ѓRѓ}ѓ“ѓh‚ЄЋw’и‚і‚к‚Д‚ў‚Ь‚№‚сЃB" +MCIERR_PARAM_OVERFLOW, "Џo—Н‚і‚к‚Ѕ•¶Ћљ—с‚Єѓoѓbѓtѓ@‚Й“ь‚иђШ‚и‚Ь‚№‚сЃBѓoѓbѓtѓ@‚МѓTѓCѓY‚р‘ќ‚в‚µ‚Д‰є‚і‚ўЃB" +MCIERR_MISSING_STRING_ARGUMENT, "Ћw’и‚і‚к‚ЅѓRѓ}ѓ“ѓh‚Й‚Н•¶Ћљ—с‚Мѓpѓ‰ѓЃЃ[ѓ^‚Є•K—v‚Е‚·ЃB" +MCIERR_BAD_INTEGER, "Ћw’и‚і‚к‚Ѕђ®ђ”’l‚Н‚±‚МѓRѓ}ѓ“ѓh‚Й‚Н–іЊш‚Е‚·ЃB" +MCIERR_PARSER_INTERNAL, "ѓfѓoѓCѓXѓhѓ‰ѓCѓo‚Є–іЊш‚ИЊ`Ћ®‚М’l‚р•Ф‚µ‚Ь‚µ‚ЅЃBђ»‘ўЊі‚ЙђV‚µ‚ўѓhѓ‰ѓCѓo‚Є–і‚ў‚©–в‚ўЌ‡‚н‚№‚Д‰є‚і‚ўЃB" +MCIERR_DRIVER_INTERNAL, "ѓfѓoѓCѓXѓhѓ‰ѓCѓo‚Й–в‘и‚Є”­ђ¶‚µ‚Ь‚µ‚ЅЃBђ»‘ўЊі‚ЙђV‚µ‚ўѓhѓ‰ѓCѓo‚Є–і‚ў‚©–в‚ўЌ‡‚н‚№‚Д‰є‚і‚ўЃB" +MCIERR_MISSING_PARAMETER, "Ћw’и‚і‚к‚ЅѓRѓ}ѓ“ѓh‚Й‚Нѓpѓ‰ѓЃЃ[ѓ^‚Є•K—v‚Е‚·ЃB" +MCIERR_UNSUPPORTED_FUNCTION, "Ћg—p‚µ‚Д‚ў‚йMCIѓfѓoѓCѓX‚НЋw’и‚і‚к‚ЅѓRѓ}ѓ“ѓh‚рѓTѓ|Ѓ[ѓg‚µ‚Д‚ў‚Ь‚№‚сЃB" +MCIERR_FILE_NOT_FOUND, "Ћw’и‚і‚к‚Ѕѓtѓ@ѓCѓ‹‚НЊ©‚В‚©‚и‚Ь‚№‚сЃBѓtѓ@ѓCѓ‹–ј‚ЖѓpѓX‚рЉm”F‚µ‚Д‰є‚і‚ўЃB" +MCIERR_DEVICE_NOT_READY, "ѓfѓoѓCѓXѓhѓ‰ѓCѓo‚МЏЂ”х‚Є‚Е‚«‚Д‚ў‚Ь‚№‚сЃB" +MCIERR_INTERNAL, "MCI‚МЏ‰Љъ‰»’†‚Й–в‘и‚Є”­ђ¶‚µ‚Ь‚µ‚ЅЃBWindows‚рЌД‹N“®‚µ‚Д‰є‚і‚ўЃB" +MCIERR_DRIVER, "ѓfѓoѓCѓXѓhѓ‰ѓCѓo‚Й–в‘и‚Є”­ђ¶‚µ‚Ь‚µ‚ЅЃBѓhѓ‰ѓCѓo‚НѓNѓЌЃ[ѓY‚і‚к‚Д‚ў‚Ь‚·ЃBѓGѓ‰Ѓ[‚ЙѓAѓNѓZѓX‚Е‚«‚Ь‚№‚сЃB" +MCIERR_CANNOT_USE_ALL, "Ћw’и‚і‚к‚ЅѓRѓ}ѓ“ѓh‚НЃuallЃv‚рѓfѓoѓCѓX–ј‚Ж‚µ‚ДЋg—p‚·‚й‚±‚Ж‚Є‚Е‚«‚Ь‚№‚сЃB" +MCIERR_MULTIPLE, "•Ўђ”‚МѓfѓoѓCѓX‚ЕѓGѓ‰Ѓ[‚Є”­ђ¶‚µ‚Ь‚µ‚ЅЃB‚З‚МѓfѓoѓCѓX‚ЕѓGѓ‰Ѓ[‚Є”­ђ¶‚µ‚Ѕ‚©Љm”F‚·‚й‚Й‚НЃAѓRѓ}ѓ“ѓh‚ЖѓfѓoѓCѓX‚р•КЊВ‚ЙЋw’и‚µ‚Д‰є‚і‚ўЃB" +MCIERR_EXTENSION_NOT_FOUND, "Ћw’и‚і‚к‚Ѕѓtѓ@ѓCѓ‹‚МЉg’ЈЋq‚©‚зѓfѓoѓCѓX‚МЋн—Ю‚р“Б’и‚Е‚«‚Ь‚№‚сЃB" +MCIERR_OUTOFRANGE, "Ћw’и‚і‚к‚ЅѓRѓ}ѓ“ѓh‚Й‘О‚µ‚ДЋw’и‚і‚к‚Ѕѓpѓ‰ѓЃЃ[ѓ^‚Н”Н€НЉO‚Е‚·ЃB" +MCIERR_FLAGS_NOT_COMPATIBLE, "Ћw’и‚і‚к‚Ѕѓpѓ‰ѓЃЃ[ѓ^‚Н“ЇЋћ‚ЙЋg—p‚Е‚«‚Ь‚№‚сЃB" +MCIERR_FILE_NOT_SAVED, "Ћw’и‚і‚к‚Ѕѓtѓ@ѓCѓ‹‚Н•Ы‘¶‚Е‚«‚Ь‚№‚с‚Е‚µ‚ЅЃBѓfѓBѓXѓN‚ЙЏ\•Є‚И‹у‚«—e—К‚Є‚ ‚й‚©ЃA‚ ‚й‚ў‚НѓlѓbѓgѓЏЃ[ѓN‚ЙђЪ‘±‚і‚к‚Д‚ў‚й‚©Љm”F‚µ‚Д‰є‚і‚ўЃB" +MCIERR_DEVICE_TYPE_REQUIRED, "Ћw’и‚і‚к‚ЅѓfѓoѓCѓX‚НЊ©‚В‚©‚и‚Ь‚№‚с‚Е‚µ‚ЅЃBѓfѓoѓCѓX‚Є‘•’…‚і‚к‚Д‚ў‚ДЃAѓfѓoѓCѓX–ј‚̂‚Â肪ђі‚µ‚ў‚©Љm”F‚µ‚Д‰є‚і‚ўЃB" +MCIERR_DEVICE_LOCKED, "Ћw’и‚і‚к‚ЅѓfѓoѓCѓX‚НѓNѓЌЃ[ѓYЏ€—ќ’†‚Е‚·ЃBђ”•b‘Т‚Б‚Д‚©‚з‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" +MCIERR_DUPLICATE_ALIAS, "Ћw’и‚і‚к‚ЅѓGѓCѓЉѓAѓX‚Н‚±‚МѓAѓvѓЉѓPЃ[ѓVѓ‡ѓ“‚Й‚ж‚Б‚ДѓGѓCѓЉѓAѓX‚Ж‚µ‚ДЋg—p‚і‚к‚Д‚ў‚Ь‚·ЃB“ЖЋ©‚МѓGѓCѓЉѓAѓX‚рЋg—p‚µ‚Д‰є‚і‚ўЃB" +MCIERR_BAD_CONSTANT, "Ћw’и‚і‚к‚Ѕѓpѓ‰ѓЃЃ[ѓ^‚Н‚±‚МѓRѓ}ѓ“ѓh‚Й‚Н–іЊш‚Е‚·ЃB" +MCIERR_MUST_USE_SHAREABLE, "ѓfѓoѓCѓXѓhѓ‰ѓCѓo‚НЋg—p’†‚Е‚·ЃBѓfѓoѓCѓX‚р‹¤—L‚·‚й‚Й‚НЃuopenЃvѓRѓ}ѓ“ѓh‚І‚Ж‚ЙЃushareableЃvѓpѓ‰ѓЃЃ[ѓ^‚рЋw’и‚µ‚Д‰є‚і‚ўЃB" +MCIERR_MISSING_DEVICE_NAME, "Ћw’и‚і‚к‚ЅѓRѓ}ѓ“ѓh‚Й‚НѓGѓCѓЉѓAѓXЃAѓtѓ@ѓCѓ‹ЃAѓhѓ‰ѓCѓo‚Ь‚Ѕ‚НѓfѓoѓCѓX–ј‚рЋw’и‚·‚й•K—v‚Є‚ ‚и‚Ь‚·ЃB" +MCIERR_BAD_TIME_FORMAT, "Ћw’и‚і‚к‚ЅЋћЉФ‚МѓtѓHЃ[ѓ}ѓbѓg‚Є–іЊш‚Е‚·ЃBЋg—p‚Е‚«‚йѓtѓHЃ[ѓ}ѓbѓg‚ЙЉЦ‚µ‚Д‚НMCI‚МѓhѓLѓ…ѓЃѓ“ѓg‚рЋQЏЖ‚µ‚Д‰є‚і‚ўЃB" +MCIERR_NO_CLOSING_QUOTE, "ѓ_ѓuѓ‹ѓNѓIЃ[ѓeЃ[ѓVѓ‡ѓ“‚Є•В‚¶‚Д‚ў‚Ь‚№‚сЃB" +MCIERR_DUPLICATE_FLAGS, "ѓpѓ‰ѓЃЃ[ѓ^‚Є“сЏd‚ЙЋw’и‚і‚к‚Д‚ў‚Ь‚·ЃB" +MCIERR_INVALID_FILE, "Ћw’и‚і‚к‚Ѕѓtѓ@ѓCѓ‹‚НЋw’и‚і‚к‚ЅMCIѓfѓoѓCѓX‚Е‚НЌДђ¶‚Е‚«‚Ь‚№‚сЃBѓtѓ@ѓCѓ‹‚Є”j‘№‚µ‚Д‚ў‚й‚©ЃAѓtѓHЃ[ѓ}ѓbѓg‚Є•sђі‚Е‚·ЃB" +MCIERR_NULL_PARAMETER_BLOCK, "ѓkѓ‹ѓpѓ‰ѓЃЃ[ѓ^‚ЄMCI‚Й“n‚і‚к‚Ь‚µ‚ЅЃB" +MCIERR_UNNAMED_RESOURCE, "ѓtѓ@ѓCѓ‹–ј‚ЄЋw’и‚і‚к‚Д‚ў‚И‚ў‚Ѕ‚Я•Ы‘¶‚Е‚«‚Ь‚№‚сЃBѓtѓ@ѓCѓ‹–ј‚рЋw’и‚µ‚Д‰є‚і‚ўЃB" +MCIERR_NEW_REQUIRES_ALIAS, "ЃunewЃvѓpѓ‰ѓЃЃ[ѓ^‚рЋg—p‚·‚йЏкЌ‡‚НѓGѓCѓЉѓAѓX‚рЋw’и‚·‚й•K—v‚Є‚ ‚и‚Ь‚·ЃB" +MCIERR_NOTIFY_ON_AUTO_OPEN, "ѓIЃ[ѓgѓIЃ[ѓvѓ“‚і‚к‚ЅѓfѓoѓCѓX‚ЙЃunotifyЃvѓtѓ‰ѓO‚рЋg—p‚·‚й‚±‚Ж‚Н‚Е‚«‚Ь‚№‚сЃB" +MCIERR_NO_ELEMENT_ALLOWED, "Ћw’и‚і‚к‚ЅѓfѓoѓCѓX‚Й‘О‚µ‚Дѓtѓ@ѓCѓ‹–ј‚рЋg—p‚·‚й‚±‚Ж‚Н‚Е‚«‚Ь‚№‚сЃB" +MCIERR_NONAPPLICABLE_FUNCTION, "Ћw’и‚і‚к‚ЅЏ‡Џ‚ЕѓRѓ}ѓ“ѓh‚рЋАЌs‚Е‚«‚Ь‚№‚сЃBѓRѓ}ѓ“ѓhѓVЃ[ѓPѓ“ѓX‚рЏCђі‚µ‚Д‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" +MCIERR_ILLEGAL_FOR_AUTO_OPEN, "ѓIЃ[ѓgѓIЃ[ѓvѓ“‚і‚к‚ЅѓfѓoѓCѓX‚Й‘О‚µ‚ДЋw’и‚і‚к‚ЅѓRѓ}ѓ“ѓh‚рЋАЌs‚Е‚«‚Ь‚№‚сЃBѓfѓoѓCѓX‚ЄѓNѓЌЃ[ѓY‚·‚й‚Ь‚Е‘Т‚Б‚Д‚©‚з‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" +MCIERR_FILENAME_REQUIRED, "ѓtѓ@ѓCѓ‹–ј‚Є–іЊш‚Е‚·ЃBѓtѓ@ѓCѓ‹–ј‚Є”јЉp8•¶Ћљ€И“а‚ЕЃAѓsѓЉѓIѓh‚Й‘±‚ў‚ДЉg’ЈЋq‚Є•t‚ў‚Д‚ў‚й‚±‚Ж‚рЉm”F‚µ‚Д‰є‚і‚ўЃB" +MCIERR_EXTRA_CHARACTERS, "ѓNѓIЃ[ѓeЃ[ѓVѓ‡ѓ“ѓ}Ѓ[ѓN‚Й€Н‚н‚к‚Ѕ•¶Ћљ—с‚Й‘±‚­—]•Є‚И•¶Ћљ‚р“Б’и‚Е‚«‚Ь‚№‚сЃB" +MCIERR_DEVICE_NOT_INSTALLED, "Ћw’и‚і‚к‚ЅѓfѓoѓCѓX‚НѓCѓ“ѓXѓgЃ[ѓ‹‚і‚к‚Д‚ў‚Ь‚№‚сЃBѓfѓoѓCѓX‚рѓCѓ“ѓXѓgЃ[ѓ‹‚·‚й‚Й‚НѓRѓ“ѓgѓЌЃ[ѓ‹ѓpѓlѓ‹“а‚МЃuѓnЃ[ѓhѓEѓFѓA‚М’З‰Б‚ЖЌнЏњЃvѓAѓvѓЊѓbѓg‚рЋg—p‚µ‚Д‰є‚і‚ўЃB" +MCIERR_GET_CD, "Ћw’и‚і‚к‚Ѕѓtѓ@ѓCѓ‹‚Ь‚Ѕ‚НMCIѓfѓoѓCѓX‚ЙѓAѓNѓZѓX‚Е‚«‚Ь‚№‚сЃBѓfѓBѓЊѓNѓgѓЉ‚р•ПЌX‚·‚й‚©ЃAѓRѓ“ѓsѓ…Ѓ[ѓ^‚рЌД‹N“®‚µ‚Д‰є‚і‚ўЃB" +MCIERR_SET_CD, "ѓAѓvѓЉѓPЃ[ѓVѓ‡ѓ“‚ЄѓfѓBѓЊѓNѓgѓЉ‚р•ПЌX‚Е‚«‚И‚ў‚Ѕ‚ЯЃAЋw’и‚і‚к‚Ѕѓtѓ@ѓCѓ‹‚Ь‚Ѕ‚НMCIѓfѓoѓCѓX‚ЙѓAѓNѓZѓX‚Е‚«‚Ь‚№‚сЃB" +MCIERR_SET_DRIVE, "ѓAѓvѓЉѓPЃ[ѓVѓ‡ѓ“‚Єѓhѓ‰ѓCѓu‚р•ПЌX‚Е‚«‚И‚ў‚Ѕ‚ЯЃAЋw’и‚і‚к‚Ѕѓtѓ@ѓCѓ‹‚Ь‚Ѕ‚НMCIѓfѓoѓCѓX‚ЙѓAѓNѓZѓX‚Е‚«‚Ь‚№‚сЃB" +MCIERR_DEVICE_LENGTH, "ѓfѓoѓCѓX–ј‚Ь‚Ѕ‚Нѓhѓ‰ѓCѓo–ј‚Н”јЉp79•¶Ћљ€И“а‚ЕЋw’и‚µ‚Д‰є‚і‚ўЃB" +MCIERR_DEVICE_ORD_LENGTH, "ѓfѓoѓCѓX–ј‚Ь‚Ѕ‚Нѓhѓ‰ѓCѓo–ј‚Н”јЉp69•¶Ћљ€И“а‚ЕЋw’и‚µ‚Д‰є‚і‚ўЃB" +MCIERR_NO_INTEGER, "Ћw’и‚і‚к‚ЅѓRѓ}ѓ“ѓh‚Й‚Нђ®ђ”’l‚Мѓpѓ‰ѓЃЃ[ѓ^‚Є•K—v‚Е‚·ЃB" +MCIERR_WAVE_OUTPUTSINUSE, "ѓtѓ@ѓCѓ‹‚рЊ»ЌЭ‚МѓtѓHЃ[ѓ}ѓbѓg‚ЕЌДђ¶‚Е‚«‚йwaveѓfѓoѓCѓX‚Н‘S‚ДЋg—p’†‚Е‚·ЃBѓfѓoѓCѓX‚Є‰р•ъ‚і‚к‚й‚Ь‚Е‘Т‚Б‚Д‚©‚з‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" +MCIERR_WAVE_SETOUTPUTINUSE, "Њ»ЌЭ‚МwaveѓfѓoѓCѓX‚НЋg—p’†‚И‚М‚ЕЌДђ¶ѓ‚Ѓ[ѓh‚ЙђЭ’и‚Е‚«‚Ь‚№‚сЃBѓfѓoѓCѓX‚Є‰р•ъ‚і‚к‚й‚Ь‚Е‘Т‚Б‚Д‚©‚з‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" +MCIERR_WAVE_INPUTSINUSE, "Њ»ЌЭ‚МѓtѓHЃ[ѓ}ѓbѓg‚Е^‰№‚Є‰В”\‚И‘S‚Д‚МwaveѓfѓoѓCѓX‚НЋg—p’†‚Е‚·ЃBѓfѓoѓCѓX‚Є‰р•ъ‚і‚к‚й‚Ь‚Е‘Т‚Б‚Д‚©‚з‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" +MCIERR_WAVE_SETINPUTINUSE, "Њ»ЌЭ‚МwaveѓfѓoѓCѓX‚НЋg—p’†‚И‚М‚Е^‰№ѓ‚Ѓ[ѓh‚ЙђЭ’и‚Е‚«‚Ь‚№‚сЃBѓfѓoѓCѓX‚Є‰р•ъ‚і‚к‚й‚Ь‚Е‘Т‚Б‚Д‚©‚з‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" +MCIERR_WAVE_OUTPUTUNSPECIFIED, "ЊЭЉ·ђ«‚М‚ ‚йЌДђ¶ѓfѓoѓCѓX‚М‚З‚к‚©‚ЄЋg—p‚і‚к‚Ь‚·ЃB" +MCIERR_WAVE_INPUTUNSPECIFIED, "ЊЭЉ·ђ«‚М‚ ‚й^‰№ѓfѓoѓCѓX‚М‚З‚к‚©‚ЄЋg—p‚і‚к‚Ь‚·ЃB" +MCIERR_WAVE_OUTPUTSUNSUITABLE, "Њ»ЌЭ‚МѓtѓHЃ[ѓ}ѓbѓg‚Еѓtѓ@ѓCѓ‹‚рЌДђ¶‚Е‚«‚йwaveѓfѓoѓCѓX‚НѓCѓ“ѓXѓgЃ[ѓ‹‚і‚к‚Д‚ў‚Ь‚№‚сЃBwaveѓfѓoѓCѓX‚рѓCѓ“ѓXѓgЃ[ѓ‹‚·‚й‚Й‚НѓRѓ“ѓgѓЌЃ[ѓ‹ѓpѓlѓ‹“а‚МЃuѓnЃ[ѓhѓEѓFѓA‚М’З‰Б‚ЖЌнЏњЃvѓAѓvѓЊѓbѓg‚рЋg—p‚µ‚Д‰є‚і‚ўЃB" +MCIERR_WAVE_SETOUTPUTUNSUITABLE,"ЌДђ¶‚µ‚悤‚Ж‚µ‚Д‚ў‚йѓfѓoѓCѓX‚НЊ»ЌЭ‚Мѓtѓ@ѓCѓ‹ѓtѓHЃ[ѓ}ѓbѓg‚р”FЋЇ‚Е‚«‚Ь‚№‚сЃB" +MCIERR_WAVE_INPUTSUNSUITABLE, "Њ»ЌЭ‚МѓtѓHЃ[ѓ}ѓbѓg‚Еѓtѓ@ѓCѓ‹‚р^‰№‚Е‚«‚йwaveѓfѓoѓCѓX‚НѓCѓ“ѓXѓgЃ[ѓ‹‚і‚к‚Д‚ў‚Ь‚№‚сЃBwaveѓfѓoѓCѓX‚рѓCѓ“ѓXѓgЃ[ѓ‹‚·‚й‚Й‚НѓRѓ“ѓgѓЌЃ[ѓ‹ѓpѓlѓ‹“а‚МЃuѓnЃ[ѓhѓEѓFѓA‚М’З‰Б‚ЖЌнЏњЃvѓAѓvѓЊѓbѓg‚рЋg—p‚µ‚Д‰є‚і‚ўЃB" +MCIERR_WAVE_SETINPUTUNSUITABLE, "^‰№‚µ‚悤‚Ж‚µ‚Д‚ў‚йѓfѓoѓCѓX‚НЊ»ЌЭ‚Мѓtѓ@ѓCѓ‹ѓtѓHЃ[ѓ}ѓbѓg‚р”FЋЇ‚Е‚«‚Ь‚№‚сЃB" +MCIERR_NO_WINDOW, "•\Ћ¦ѓEѓBѓ“ѓhѓE‚Є‚ ‚и‚Ь‚№‚сЃB" +MCIERR_CREATEWINDOW, "ѓEѓBѓ“ѓhѓE‚МЌмђ¬‚Ь‚Ѕ‚НЋg—p‚Є‚Е‚«‚Ь‚№‚сЃB" +MCIERR_FILE_READ, "Ћw’и‚µ‚Ѕѓtѓ@ѓCѓ‹‚р“З‚ЭЌћ‚Я‚Ь‚№‚сЃBѓtѓ@ѓCѓ‹‚Є‘¶ЌЭ‚·‚й‚©Љm”F‚µ‚Д‰є‚і‚ўЃA‚ ‚й‚ў‚НѓfѓBѓXѓN‚©ѓlѓbѓgѓЏЃ[ѓNђЪ‘±‚рЉm”F‚µ‚Д‰є‚і‚ўЃB" +MCIERR_FILE_WRITE, "Ћw’и‚і‚к‚Ѕѓtѓ@ѓCѓ‹‚ЙЏ‘‚«Ќћ‚Я‚Ь‚№‚сЃBѓfѓBѓXѓN‚ЙЏ\•Є‚И‹у‚«—e—К‚Є‚ ‚й‚©ЃA‚ ‚й‚ў‚НѓlѓbѓgѓЏЃ[ѓN‚ЙђЪ‘±‚і‚к‚Д‚ў‚й‚©Љm”F‚µ‚Д‰є‚і‚ўЃB" +MCIERR_SEQ_DIV_INCOMPATIBLE, "Ѓuѓ\ѓ“ѓOѓ|ѓCѓ“ѓ^Ѓv‚ЖSMPTE‚МЋћЉФѓtѓHЃ[ѓ}ѓbѓg‚р“ЇЋћ‚ЙЋg—p‚·‚й‚±‚Ж‚Н‚Е‚«‚Ь‚№‚сЃB" +MCIERR_SEQ_NOMIDIPRESENT, "MIDIѓfѓoѓCѓX‚НѓCѓ“ѓXѓgЃ[ѓ‹‚і‚к‚Д‚ў‚Ь‚№‚сЃBMIDIѓhѓ‰ѓCѓo‚рѓCѓ“ѓXѓgЃ[ѓ‹‚·‚й‚Й‚НѓRѓ“ѓgѓЌЃ[ѓ‹ѓpѓlѓ‹“а‚МЃuѓnЃ[ѓhѓEѓFѓA‚М’З‰Б‚ЖЌнЏњЃvѓAѓvѓЊѓbѓg‚рЋg—p‚µ‚Д‰є‚і‚ўЃB" +MCIERR_SEQ_PORT_INUSE, "Ћw’и‚і‚к‚ЅMIDIѓ|Ѓ[ѓg‚НЋg—p’†‚Е‚·ЃBMIDIѓ|Ѓ[ѓg‚ЄЉJ•ъ‚і‚к‚й‚Ь‚Е‘Т‚Б‚Д‚©‚з‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" +MCIERR_SEQ_PORT_MAPNODEVICE, "MIDIѓ}ѓbѓp‚МђЭ’и‚ЄѓVѓXѓeѓЂ‚Й‘•’…‚і‚к‚Д‚ў‚И‚ўѓfѓoѓCѓX‚рЋQЏЖ‚µ‚Д‚ў‚Ь‚·ЃBђЭ’и‚р•ПЌX‚·‚й‚Й‚НѓRѓ“ѓgѓЌЃ[ѓ‹ѓpѓlѓ‹‚МЃuMIDIѓ}ѓbѓpЃvѓAѓvѓЊѓbѓg‚рЋg—p‚µ‚Д‰є‚і‚ўЃB" +MCIERR_SEQ_PORT_MISCERROR, "Ћw’и‚і‚к‚Ѕѓ|Ѓ[ѓg‚ЕѓGѓ‰Ѓ[‚Є”­ђ¶‚µ‚Ь‚µ‚ЅЃB" +MCIERR_SEQ_PORT_NONEXISTENT, "Ћw’и‚і‚к‚ЅMIDIѓfѓoѓCѓX‚НѓVѓXѓeѓЂ‚Й‘•’…‚і‚к‚Д‚ў‚Ь‚№‚сЃBMIDIѓfѓoѓCѓX‚рѓCѓ“ѓXѓgЃ[ѓ‹‚·‚й‚Й‚НѓRѓ“ѓgѓЌЃ[ѓ‹ѓpѓlѓ‹“а‚МЃuѓnЃ[ѓhѓEѓFѓA‚М’З‰Б‚ЖЌнЏњЃvѓAѓvѓЊѓbѓg‚рЋg—p‚µ‚Д‰є‚і‚ўЃB" +MCIERR_SEQ_PORTUNSPECIFIED, "ѓVѓXѓeѓЂ‚ЙЊ»ЌЭ‚МMIDIѓ|Ѓ[ѓg‚ЄЋw’и‚і‚к‚Д‚ў‚Ь‚№‚сЃB" +MCIERR_SEQ_TIMER, "‘S‚Д‚Мѓ}ѓ‹ѓ`ѓЃѓfѓBѓAѓ^ѓCѓ}‚Н‘ј‚МѓAѓvѓЉѓPЃ[ѓVѓ‡ѓ“‚Й‚ж‚Б‚ДЋg—p‚і‚к‚Д‚ў‚Ь‚·ЃBѓ^ѓCѓ}‚рЋg—p‚µ‚Д‚ў‚йѓAѓvѓЉѓPЃ[ѓVѓ‡ѓ“‚р€к‚ВЏI—№‚µ‚Д‚©‚з‚в‚и’ј‚µ‚Д‰є‚і‚ўЃB" + +END diff --git a/reactos/lib/winmm/winmm_Nl.rc b/reactos/lib/winmm/winmm_Nl.rc new file mode 100644 index 00000000000..4a0c481bec7 --- /dev/null +++ b/reactos/lib/winmm/winmm_Nl.rc @@ -0,0 +1,127 @@ +/* + * Copyright 1999 Klaas van Gend + * + * 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 + */ + +STRINGTABLE LANGUAGE LANG_DUTCH, SUBLANG_DEFAULT +BEGIN + +/* MMSYS errors */ +MMSYSERR_NOERROR, "De gespecificeerde opdracht is uitgevoerd." +MMSYSERR_ERROR, "Ongedefinieerde fout van buitenaf." +MMSYSERR_BADDEVICEID, "Een apparaat ID werd gebruikt dat buiten de grenzen van uw systeem ligt." +MMSYSERR_NOTENABLED, "De driver is niet geactiveerd." +MMSYSERR_ALLOCATED, "Het gewenste apparaat is in gebruik. Wacht totdat het vrijkomt en probeer het dan opnieuw." +MMSYSERR_INVALHANDLE, "De gespecificeerde apparaatverwijzing is ongeldig." +MMSYSERR_NODRIVER, "Er is geen driver geinstalleerd op uw systeem !\n" +MMSYSERR_NOMEM, "Er is niet genoeg geheugen beschikbaar voor deze taak. Sluit enkele programma's af om meer geheugen vrij te krijgen en doe dan nog een poging." +MMSYSERR_NOTSUPPORTED, "Deze functie wordt niet ondersteund. Gebruik de 'Capabilities' functie om uit te zoeken welke toepassingen en boodschappen de driver ondersteund." +MMSYSERR_BADERRNUM, "Een niet binnen het systeem bekend foutnummer werd gebruikt." +MMSYSERR_INVALFLAG, "Een ongeldige vlag werd aan een systeemfunctie gevoerd." +MMSYSERR_INVALPARAM, "Een systeemfunctie kreeg een ongeldige parameter te eten." + +/* WAVE errors */ +WAVERR_BADFORMAT, "Het aangegeven formaat wordt niet ondersteund of geconverteerd. Gebruik de 'Capabilities' functie om de ondersteunde formaten te vinden" +WAVERR_STILLPLAYING, "Kan deze opdracht niet uitvoeren zolang afgespeeld wordt. Herstart het apparaat of wacht totdat het apparaat klaar is met spelen." +WAVERR_UNPREPARED, "De Wave Header was niet aanwezig. Gebruik de 'Prepare' functie om de Header te genereren en probeer het dan opnieuw." +WAVERR_SYNC, "Kan het apparaat niet openen zonder de WAVE_ALLOWSYNC vlag. Zet de vlag en probeer opnieuw." + +/* MIDI errors */ +MIDIERR_UNPREPARED, "De MIDI Header was niet aanwezig. Gebruik de 'Prepare' functie om de Header te genereren en probeer het dan opnieuw." +MIDIERR_STILLPLAYING, "Kan deze opdracht niet uitvoeren zolang afgespeeld wordt. Herstart het apparaat of wacht totdat het apparaat klaar is met spelen." +MIDIERR_NOMAP, "Er is geen MIDI Map gevonden. Er zou een driver probleem kunnen zijn of de MIDIMAP.CFG file is verminkt of afwezig." +MIDIERR_NOTREADY, "De poort is bezig data ter versturen naar het apparaat. Wacht totdat alle data is verstuurd en probeer het dan opnieuw." +MIDIERR_NODEVICE, "De huidige MIDI Mapper setup verwijst naar een MIDI apparaat dat niet op het systeem aanwezig is. Gebruik MIDI Mapper om de instellingen aan te passen." +MIDIERR_INVALIDSETUP, "De huidige MIDI setup is beschadigd. Kopieer de originele MIDIMAP.CFG file naar de Windows SYSTEM directory en probeer het daarna weer." + +/* MCI errors */ +MCIERR_INVALID_DEVICE_ID, "Ongeldige MCI apparaat ID. Gebruik de teruggegeven ID als u dit MCI apparaat opent." +MCIERR_UNRECOGNIZED_KEYWORD, "De driver kant de gegeven opdracht parameter niet herkennen." +MCIERR_UNRECOGNIZED_COMMAND, "De driver kant de gegeven opdracht niet herkennen." +MCIERR_HARDWARE, "ER is een probleem met uw media apparaat. Controleer of 't correct werkt of neem contact op met de leverancier." +MCIERR_INVALID_DEVICE_NAME, "The specified device is not open or is not recognized by MCI." +MCIERR_OUT_OF_MEMORY, "Er is niet genoeg geheugen beschikbaar voor deze taak. Sluit enkele programma's af om meer geheugen vrij te krijgen en probeer opnieuw." +MCIERR_DEVICE_OPEN, "Een apparaat met die naam is al in gebruik als alias door deze applicatie. Gebruik een uniek alias." +MCIERR_CANNOT_LOAD_DRIVER, "Er is een onbekende fout ontstaan tijdens het laden van de apparaat driver." +MCIERR_MISSING_COMMAND_STRING, "Er was geen opdracht opgegeven." +MCIERR_PARAM_OVERFLOW, "De output string was te groot om in de antwoordbuffer te passen. Vergroot de buffer." +MCIERR_MISSING_STRING_ARGUMENT, "De gegeven opdracht vereist een character-string parameter. Lever er dus een aan s.v.p." +MCIERR_BAD_INTEGER, "De gegeven integer is niet geldig bij dit commando." +MCIERR_PARSER_INTERNAL, "De apparaat driver retourneerde een ongeldige waarde. Vraag de fabrikant om een andere driver." +MCIERR_DRIVER_INTERNAL, "Er is een probleem met de apparaat driver. Vraag de fabrikant om een andere driver." +MCIERR_MISSING_PARAMETER, "De gegeven opdracht benodigt een parameter. Vult u die a.u.b. in." +MCIERR_UNSUPPORTED_FUNCTION, "Het MCI apparaat dat u gebruikt ondersteund het gegeven commando niet." +MCIERR_FILE_NOT_FOUND, "Kan het opgegeven bestand niet vinden. Zorg ervoor dat het pad en de bestandsnaam correct zijn." +MCIERR_DEVICE_NOT_READY, "De apparaat driver is niet gereed." +MCIERR_INTERNAL, "Tijdens het initialiseren van MCI onstond een probleem. Probeer dit te verhelpen door Windows opnieuw te starten." +MCIERR_DRIVER, "Er is een probleem met de apparaat driver. Daarom is de driver afgesloten. Derhalve een toegangsfout." +MCIERR_CANNOT_USE_ALL, "Kan 'all' niet gebruiken als apparaat naam bij het opgegeven commando." +MCIERR_MULTIPLE, "In meer dan een apparaat zijn fouten opgetreden. Geef elk commando en apparaat apart om te achterhalen welke apparaten fouten veroorzaken." +MCIERR_EXTENSION_NOT_FOUND, "Kan het apparaat type niet achterhalen uit de gegeven bestands-extensie." +MCIERR_OUTOFRANGE, "De gegeven parameter is buiten het bereik van het opgegeven commando." +MCIERR_FLAGS_NOT_COMPATIBLE, "De gegeven parameters kunnen niet samen gebruikt worden." +MCIERR_FILE_NOT_SAVED, "Kan de opgegeven file niet saven. Zorg ervoor dat er voldoende diskruimte is of dat u nog steeds met het netwerk verbonden bent." +MCIERR_DEVICE_TYPE_REQUIRED, "Kan het opgegeven apparaat niet vinden. Verzeker u ervan dat het correct geinstalleerd is en dat de apparaatnaam correct is opgegeven." +MCIERR_DEVICE_LOCKED, "Het opgegeven apparaat wordt nu gesloten. Wacht svp. enkele seconden en probeer het dan opnieuw." +MCIERR_DUPLICATE_ALIAS, "Het gegeven alias is al in gebruik door dit programma. Gebruik een unieke alias." +MCIERR_BAD_CONSTANT, "De gegeven parameters is ongeldig bij het gegeven commando." +MCIERR_MUST_USE_SHAREABLE, "De apparaat driver is al in gebruik. Om het te delen, gebruik de 'deelbaar' parameter met elk 'open' commando." +MCIERR_MISSING_DEVICE_NAME, "Het gegeven commando vereist een alias, bestand, driver of apparaatnaam. Geeft u er svp een in." +MCIERR_BAD_TIME_FORMAT, "De gegeven waarde voor het tijdsformaat is ongeldig. Zoek in de MCI handleidingen naar geldige formaten." +MCIERR_NO_CLOSING_QUOTE, "Een afsluitende dubbele apostroph ontbreekt van de parameter waarde. Geeft u er svp een in." +MCIERR_DUPLICATE_FLAGS, "Een parameter of waarde werd dubbel opgegeven. Doe dat svp maar een keer." +MCIERR_INVALID_FILE, "De gegeven file kan niet op het MCI apparaat worden afgespeeld. Het bestand is misschien corrupt of niet in het juiste formaat." +MCIERR_NULL_PARAMETER_BLOCK, "Een leeg parameter block werd doorgegeven aan MCI." +MCIERR_UNNAMED_RESOURCE, "Kan niet saven naar bestand zonder naam. Geef een bestandsnaam svp." +MCIERR_NEW_REQUIRES_ALIAS, "U moet een alias opgeven als u de 'new' parameter gebruikt." +MCIERR_NOTIFY_ON_AUTO_OPEN, "Kan de 'notify' vlag niet gebruiken met automatisch geopende apparaten." +MCIERR_NO_ELEMENT_ALLOWED, "Kan voor het huidige apparaat geen bestandsnaam gebruiken." +MCIERR_NONAPPLICABLE_FUNCTION, "Kan de opgegeven commando's niet in deze volgorde uitvoeren. Corrigeer de commandoreeks en probeer opnieuw." +MCIERR_ILLEGAL_FOR_AUTO_OPEN, "Kan het opgegeven commando niet uitvoeren op een automatisch geopend apparaat. Wacht todat het apparaat is afgesloten en probeer dan opnieuw." +MCIERR_FILENAME_REQUIRED, "De bestandsnaam is ongeldig. Zorg ervoor dat de bestandsnaam aan het 8.3 formaat voldoet." +MCIERR_EXTRA_CHARACTERS, "Het is niet mogelijk om extra lettertekens toe te voegen na een string in aanhalingstekens." +MCIERR_DEVICE_NOT_INSTALLED, "Het opgegeven apparaat is niet geinstalleerd op het systeem. Gebruik de 'Drivers'-optie in het Configuratiescherm om het apparaat te installeren." +MCIERR_GET_CD, "Kan het opgegeven bestand of MCI apparaat niet openen. Probeer de directory te wijzigen of de computer opnieuw te starten." +MCIERR_SET_CD, "Kan het opgegeven bestand of MCI apparaat niet openen omdat de applicatie de directory niet kan wijzigen." +MCIERR_SET_DRIVE, "Kan het opgegeven bestand of MCI apparaat niet openen omdat de applicatie de directory niet kan wijzigen." +MCIERR_DEVICE_LENGTH, "Geef een apparaat of driver naam op met minder dan 79 lettertekens." +MCIERR_DEVICE_ORD_LENGTH, "Geef een apparaat of driver naam op met minder dan 79 lettertekens." +MCIERR_NO_INTEGER, "Het gegeven commando vereist een integer parameter. Svp geef er eentje." +MCIERR_WAVE_OUTPUTSINUSE, "Alle WAVE-apparaten die in staat zijn om een bestand in dit formaat af te spelen, zijn in gebruik. Wacht totdat een WAVE apparaat vrij is en probeer het dan opnieuw." +MCIERR_WAVE_SETOUTPUTINUSE, "Kan het huidige WAVE-apparaat niet gebruiken omdat het in gebruik is. Wacht totdat het apparaat vrij is en probeer het dan opnieuw." +MCIERR_WAVE_INPUTSINUSE, "Alle WAVE-apparaten die in staat zijn om een bestand in dit formaat op te nemen, zijn in gebruik. Wacht totdat een WAVE apparaat vrij is en probeer het dan opnieuw." +MCIERR_WAVE_SETINPUTINUSE, "Kan het huidige WAVE-apparaat niet gebruiken om op te nemen omdat het in gebruik is. Wacht totdat het apparaat vrij is en probeer het dan opnieuw." +MCIERR_WAVE_OUTPUTUNSPECIFIED, "Elk compatible WAVE afspeelapparaat kan worden gebruikt." +MCIERR_WAVE_INPUTUNSPECIFIED, "Elk compatible WAVE opnameapparaat kan worden gebruikt." +MCIERR_WAVE_OUTPUTSUNSUITABLE, "Er is momenteel geen WAVE apparaat geinstalleerd dat bestanden in het huidige formaat kan afspelen. Gebruik de 'Drivers' optie om zo'n WAVE apparaat te installeren." +MCIERR_WAVE_SETOUTPUTUNSUITABLE,"Het apparaat waar u probeert mee af te spelen is niet in staat om het huidige formaat te herkennen." +MCIERR_WAVE_INPUTSUNSUITABLE, "Er is momenteel geen WAVE apparaat geinstalleerd dat bestanden in het huidige formaat kan opnemen. Gebruik de 'Drivers' optie om zo'n WAVE apparaat te installeren." +MCIERR_WAVE_SETINPUTUNSUITABLE, "Het apparaat waar u probeert mee op te nemen is niet in staat om het huidige formaat te herkennen." +MCIERR_NO_WINDOW, "Er is geen weergave venster." +MCIERR_CREATEWINDOW, "Kon geenvenster maken of gebruiken." +MCIERR_FILE_READ, "Kan het opgegeven bestand niet lezen. Contrleer of het bestand nog steeds bestaat, en controleer de verbinding naar de disk of het netwerk." +MCIERR_FILE_WRITE, "Kan het opgegeven bestand niet schrijven. Contrleer of er voldoende diskruimte is, en controleer de verbinding naar het netwerk." + +MCIERR_SEQ_DIV_INCOMPATIBLE, "Van tijdformaten van 'song pointer' en SMPTE kan er maar een in gebruik zijn. U kunt ze niet beide tegelijkertijd gebruiken." +MCIERR_SEQ_NOMIDIPRESENT, "Het systeem heeft geen MIDI apparaten geinstalleerd. Gebruik de 'Drivers'-optie in het Configuratiescherm om een MIDI apparaat te installeren." +MCIERR_SEQ_PORT_INUSE, "De opgegeven MIDI poort is al in gebruik. Wacht totdat deze vrij is en probeer dan opnieuw." +MCIERR_SEQ_PORT_MAPNODEVICE, "De huidige MIDI Mapper setup verwijst naar een MIDI apparaat dat niet op het systeem is geinstalleerd. Gebruik de 'MIDI mapper'-optie in het Configuratiescherm om een MIDI apparaat te installeren." +MCIERR_SEQ_PORT_MISCERROR, "Er is error opgetreden bij de opgegeven poort." +MCIERR_SEQ_PORT_NONEXISTENT, "Het opgegeven MIDI Mapper apparaat is niet op het systeem geinstalleerd. Gebruik de 'MIDI mapper'-optie in het Configuratiescherm om het te installeren." +MCIERR_SEQ_PORTUNSPECIFIED, "Het systeem heeft momenteel geen aangewezen MIDI poort." +MCIERR_SEQ_TIMER, "Alle multimedia timers zijn in gebruik door andere applicaties. Sluit een van deze applicaties, probeer het dan opnieuw." + +END diff --git a/reactos/lib/winmm/winmm_Pt.rc b/reactos/lib/winmm/winmm_Pt.rc new file mode 100644 index 00000000000..f5371cc854e --- /dev/null +++ b/reactos/lib/winmm/winmm_Pt.rc @@ -0,0 +1,127 @@ +/* + * Copyright 1999 Gustavo Junior Alves + * Copyright 2003 Marcelo Duarte + * + * 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 + */ + +STRINGTABLE LANGUAGE LANG_PORTUGUESE, SUBLANG_DEFAULT +BEGIN + +/* MMSYS errors */ +MMSYSERR_NOERROR, "O comando especificado foi descarregado." +MMSYSERR_ERROR, "Erro externo indefinido." +MMSYSERR_BADDEVICEID, "O ID do dispositivo utilizado estб fora dos parвmetros do seu sistema." +MMSYSERR_NOTENABLED, "O driver nгo foi habilitado." +MMSYSERR_ALLOCATED, "O dispositivo especificado jб estб em uso. Aguarde atй que seja liberado, e entгo tente novamente." +MMSYSERR_INVALHANDLE, "O handle do dispositivo especificado й invбlido." +MMSYSERR_NODRIVER, "Nгo hб nenhum driver instalado em seu sistema !\n" +MMSYSERR_NOMEM, "Nгo hб memуria disponнvel suficiente para essa tarefa. Feche uma ou mais aplicaзхes para aumentar a memуria disponнvel, e entгo tente novamente." +MMSYSERR_NOTSUPPORTED, "Essa funзгo nгo й suportada. Utilize a funзгo Capacidades para determinar quais funзхes e mensagens o driver suporta." +MMSYSERR_BADERRNUM, "Um nъmero de erro foi especificado e nгo estб definido em seu sistema." +MMSYSERR_INVALFLAG, "Um flag invбlido foi passado para uma funзгo do sistema." +MMSYSERR_INVALPARAM, "Um parвmetro invбlido foi passado para uma funзгo do sistema." + +/* WAVE errors */ +WAVERR_BADFORMAT, "O formato especificado nгo й suportado ou nгo pode ser traduzido. Use a funзгo Capacidades para determinar os formatos suportados." +WAVERR_STILLPLAYING, "Nгo й possнvel executar esta operaзгo enquando os dados de mнdia estiverem tocando. Reinicie o dispositivo, ou aguarde atй o tйrmino da execuзгo." +WAVERR_UNPREPARED, "O cabeзalho do wave nгo estб preparado. Use a funзгo Preparar para preparar o cabeзalho, e entгo tente novamente." +WAVERR_SYNC, "Nгo й possнvel abrir o dispositivo sem utilizar a flag WAVE_ALLOWSYNC. Use a flag, e entгo tente novamente." + +/* MIDI errors */ +MIDIERR_UNPREPARED, "O cabeзalho MIDI nгo estб preparado. Use a funзгo Preparar para preparar o cabeзalho, e entгo tente novamente." +MIDIERR_STILLPLAYING, "Nгo й possнvel executar esta operaзгo enquanto os dados da mнdia estiverem sendo executados. Reinicie o dispositivo, ou aguarde atй os dados terminarem de ser tocados." +MIDIERR_NOMAP, "O mapa MIDI nгo foi encontrado. Talvez seja um problema com o driver, ou o arquivo MIDIMAP.CFG pode estar corrompido ou faltando." +MIDIERR_NOTREADY, "A porta estб transmitindo dados para o dispositivo. Aguarde atй os dados terminarem de ser transmitidos, e entгo tente novamente." +MIDIERR_NODEVICE, "A configuraзгo atual do MIDI Mapper refere-se a um dispositivo MIDI que nгo estб instalado no sistema. Use MIDI Mapper para editar a configuraзгo." +MIDIERR_INVALIDSETUP, "A configuraзгo atual do MIDI estб corrompida. Copie o arquivo original MIDIMAP.CFG para o diretуrio Windows SYSTEM, e entгo tente novamente." + +/* MCI errors */ +MCIERR_INVALID_DEVICE_ID, "ID invбlido do dispositivo MCI. Use o ID retornado para abrir o dispositivo MCI." +MCIERR_UNRECOGNIZED_KEYWORD, "O driver nгo pode reconhecer o parвmetro de comando especificado." +MCIERR_UNRECOGNIZED_COMMAND, "O driver nгo pode reconhecer o comando especificado." +MCIERR_HARDWARE, "Hб um problema com seu dispositivo de mнdia. Tenha certeza que esteja funcionando corretamente ou contacte o fabricante do dispositivo." +MCIERR_INVALID_DEVICE_NAME, "O dispositivo especificado nгo estб aberto ou nгo й reconhecido pelo MCI." +MCIERR_OUT_OF_MEMORY, "Nгo jб memуria disponнvel sufuciente para esta tarefa.\nFeche uma ou mais aplicaзхes para aumentar a memуria disponнvel, e entгo tente novamente." +MCIERR_DEVICE_OPEN, "O nome do dispositivo jб estб sendo usado como um alias por esta aplicaзгo. Use um alias ъnico." +MCIERR_CANNOT_LOAD_DRIVER, "Aconteceu um problema desconhecido enquanto carregava o driver do dispositivo especificado." +MCIERR_MISSING_COMMAND_STRING, "Nenhum comando foi especificado." +MCIERR_PARAM_OVERFLOW, "A string de saнda foi muito grande para ser colocada no buffer de retorno. Aumente o tamanho do buffer." +MCIERR_MISSING_STRING_ARGUMENT, "O comando especificado requer como parвmetro uma string de caracters. Por favor, forneзa-a." +MCIERR_BAD_INTEGER, "O inteiro especificado й invбlido para este comando." +MCIERR_PARSER_INTERNAL, "O driver do dispositivo retornou um tipo invбlido. Verifique com o fabricante do dispositivo como obter um novo driver." +MCIERR_DRIVER_INTERNAL, "Existe um problema com o seu driver de dispositivo. Verifique com o fabricante do dispositivo como obter um novo driver." +MCIERR_MISSING_PARAMETER, "O comando especificado requer um parвmetro. Por favor forneзa-o." +MCIERR_UNSUPPORTED_FUNCTION, "O dispositivo MCI que vocк estб usando nгo suporta o comando especificado." +MCIERR_FILE_NOT_FOUND, "Nгo й possнvel encontrar o arquivo especificado. Certifique-se que o caminho e o nome do arquivo estгo corretos." +MCIERR_DEVICE_NOT_READY, "O driver do dispositivo nгo estб preparado." +MCIERR_INTERNAL, "Um problema ocorreu na inicializaзгo do MCI. Tente reiniciar o Windows." +MCIERR_DRIVER, "Hб um problema com o driver do dispositivo. O driver foi fechado. Nгo й possнvel acessar o erro." +MCIERR_CANNOT_USE_ALL, "Nгo й possнvel usar 'all' como nome do dispositivo com o comando especificado." +MCIERR_MULTIPLE, "Erros ocorreram em mais de um dispositivo. Especifique cada comando e dispositivo separadamente para determinar quais dispositivos causaram o erro." +MCIERR_EXTENSION_NOT_FOUND, "Nгo й possнvel determinar o tipo de dispositivo dada a extensгo de arquivo." +MCIERR_OUTOFRANGE, "O parвmetro especificado estб fora da escala para o comando especificado." +MCIERR_FLAGS_NOT_COMPATIBLE, "Os parвmetros especificados nгo podem ser utilizados juntos." +MCIERR_FILE_NOT_SAVED, "Nгo й possнvel salvar o arquivo especificado. Certifique-se que tenha espaзo em disco suficiente ou que ainda esteja conectado a rede." +MCIERR_DEVICE_TYPE_REQUIRED, "Nгo й possнvel encontrar o dispositivo especificado. Certifique-se que estб instalado ou que o nome do dispositivo foi escrito corretamente." +MCIERR_DEVICE_LOCKED, "O dispositivo especificado estб sendo fechado agora. Aguarde alguns segundos, e entгo tente novamente." +MCIERR_DUPLICATE_ALIAS, "O alias especificado jб estб sendo utilizado nesta aplicaзгo. Use um alias ъnico." +MCIERR_BAD_CONSTANT, "O parвmetro especificado й invбlido para este comando." +MCIERR_MUST_USE_SHAREABLE, "O driver de dispositivo jб estб em uso. Para compartilha-lo, use o parвmetro 'shareable' para cada comando 'open'." +MCIERR_MISSING_DEVICE_NAME, "O comando especificado requer um alias, arquivo, driver ou nome de dispositivo. Por favor, forneзa um." +MCIERR_BAD_TIME_FORMAT, "O valor especificado para o formato de hora й invбlido. Verifique na documentaзгo do MCI sobre formatos vбlidos." +MCIERR_NO_CLOSING_QUOTE, "A aspa-dupla de fechamento estб faltando para o valor do parвmetro. Por favor forneзa uma." +MCIERR_DUPLICATE_FLAGS, "Um parвmetro ou valor foi especificado duas vezes. Apenas especifique-o uma ъnica vez." +MCIERR_INVALID_FILE, "O arquivo espeficidado nгo pode ser tocado no dispositivo MCI especificado. O arquivo pode estar corrompido, ou nгo estar no formato correto." +MCIERR_NULL_PARAMETER_BLOCK, "Um bloco de parвmetro nulo foi passado para o MCI.." +MCIERR_UNNAMED_RESOURCE, "Nгo й possнvel salvar um arquivo sem nome. Por favor forneзa um nome de arquivo." +MCIERR_NEW_REQUIRES_ALIAS, "Vocк precisa especificar um alias quando utilizar o parвmetro 'new'." +MCIERR_NOTIFY_ON_AUTO_OPEN, "Nгo й possнvel utilizar o flag 'notify' em dispositivos abertos automaticamente." +MCIERR_NO_ELEMENT_ALLOWED, "Nгo й possнvel usar um nome de arquivo com o dispositivo especificado." +MCIERR_NONAPPLICABLE_FUNCTION, "Nгo й possнvel descarregar os comandos na ordem especificada. Corrija a sequкncia dos comandos, e entгo tente novamente." +MCIERR_ILLEGAL_FOR_AUTO_OPEN, "Nгo й possнvel descarregar o comando especificado em um dispositivo aberto automanticamente. Aguarde atй o dispositivo ser fechado, e entгo tente novamente." +MCIERR_FILENAME_REQUIRED, "O nome do arquivo й invбlido. Certifique-se que o nome do arquivo nгo й maior que 8 caracteres, seguido por um ponto e uma extensгo." +MCIERR_EXTRA_CHARACTERS, "Nгo й possнvel especificar caracteres extras apуs uma string entre aspas." +MCIERR_DEVICE_NOT_INSTALLED, "O dispositivo especificado nгo esta instalado no sistema. Utilize o opзгo Drivers no Painel de Controle para instalar o dispositivo." +MCIERR_GET_CD, "Nгo й possнvel acessar o arquivo especificado ou o dispositivo MCI. Tente mudar de diretуrio ou reiniciar seu computador." +MCIERR_SET_CD, "Nгo й possнvel acessar o arquivo especificado ou o dispositivo MCI porque a aplicaзгo nгo pode mudar de diretуrio." +MCIERR_SET_DRIVE, "Nгo posso acessar o arquivo especificado ou o dispositivo MCI porque a aplicaзгo nгo pode mudar de drive." +MCIERR_DEVICE_LENGTH, "Especifique um dispositivo ou nome de driver que seja menor que 79 caracteres." +MCIERR_DEVICE_ORD_LENGTH, "Especifique um dispositivo ou nome de driver que seja menor que 69 caracteres." +MCIERR_NO_INTEGER, "O comando especificado requer um parвmetro inteiro. Por favor forneзa um." +MCIERR_WAVE_OUTPUTSINUSE, "Todos os dispositivos wave que podem tocar arquivos no formato atual estгo em uso. Aguarde atй um dispositivo wave ficar ocioso e entгo tente novamente." +MCIERR_WAVE_SETOUTPUTINUSE, "Nгo й possнvel definir o dispositivo wave atual para tocar porque estб em uso. Aguarde atй o dispositivo ficar ocioso e entгo tente novamente." +MCIERR_WAVE_INPUTSINUSE, "Todos os dispositivos wave que podem gravar arquivos no formato atual estгo em uso. Aguarde atй o dispositivo wave ficar ocioso, e entгo tente novamente." +MCIERR_WAVE_SETINPUTINUSE, "Nгo foi possivel definir o dispositivo wave corrente para gravar porque ele estб em uso. Aguarde atй ele ficar livre, e entгo tente novamente." +MCIERR_WAVE_OUTPUTUNSPECIFIED, "Qualquer dispositivo tocador compatнvel com o formato wave pode ser utilizado." +MCIERR_WAVE_INPUTUNSPECIFIED, "Qualquer dispositivo gravador compatнvel com o formato wave pode ser utilizado." +MCIERR_WAVE_OUTPUTSUNSUITABLE, "Nenhum dispositivo wave que possa tocar arquivos no formato wave estб instalado. Use a opзгo Drivers para instalar o dispositivo wave." +MCIERR_WAVE_SETOUTPUTUNSUITABLE,"O dispositivo que vocк estб tentando tocar nгo reconhece o formato do arquivo atual." +MCIERR_WAVE_INPUTSUNSUITABLE, "Nenhum dispositivo wave que possa gravar arquivos no formato atual estб instalado. Use o opзгo Drivers para instalar o dispositivo wave." +MCIERR_WAVE_SETINPUTUNSUITABLE, "O dispositivo de onde vocк estб tentando gravar nгo pode reconhecer o formato do arquivo atual." +MCIERR_NO_WINDOW, "Nгo hб nenhuma janela de visualizaзгo." +MCIERR_CREATEWINDOW, "Nгo й possнvel criar ou utilizar a janela." +MCIERR_FILE_READ, "Nгo й possнvel ler o arquivo especificado. Certifique-se que o arquivo ainda estб presente, ou verifique seu disco ou conecзгo de rede." +MCIERR_FILE_WRITE, "Nгo й possнvel gravar no arquivo especificado. Certifique-se que vocк possui espaзo em disco suficiente ou que ainda esteja conectado na rede." +MCIERR_SEQ_DIV_INCOMPATIBLE, "O formato de hora do ""song pointer"" e SMPTE sгo mutualmente exclusivos. Vocк nгo pode utilizб-los juntos." +MCIERR_SEQ_NOMIDIPRESENT, "O sistema nгo possui dispositivos MIDI instalados. Use a opзгo Drivers no Painel de Controle para instalar um driver MIDI." +MCIERR_SEQ_PORT_INUSE, "A porta MIDI especificada jб esta em uso. Aguarde atй que esteja livre, e tente novamente." +MCIERR_SEQ_PORT_MAPNODEVICE, "A configuraзгo atual do MIDI Mapper refere-se a um dispositivo MIDI que nгo estб instalado em seu sistema. Use a opзгo MIDI Mapper do Painel de Controle para editar a configuraзгo." +MCIERR_SEQ_PORT_MISCERROR, "Um erro ocorreu com a porta especificada." +MCIERR_SEQ_PORT_NONEXISTENT, "O dispositivo MIDI especificado nгo estб instalado em seu sistema. Use a opзгo Drivers no Painel de Controle para instalar um dispositivo MIDI." +MCIERR_SEQ_PORTUNSPECIFIED, "O sistema nгo tкm atualmente uma porta MIDI especificada." +MCIERR_SEQ_TIMER, "Todos os temporizadores de multimнdia estгo sendo utilizados por outras aplicaзхes. Feche uma dessas aplicaзхes, entгo tente novamente." + +END diff --git a/reactos/lib/winmm/winmm_Ru.rc b/reactos/lib/winmm/winmm_Ru.rc new file mode 100644 index 00000000000..9744375f9c4 --- /dev/null +++ b/reactos/lib/winmm/winmm_Ru.rc @@ -0,0 +1,130 @@ +/* + * Copyright 2000 Oleg Korda + * + * 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 + */ + +STRINGTABLE LANGUAGE LANG_RUSSIAN, SUBLANG_NEUTRAL +BEGIN + +/* Russian strings in CP1251 */ + +/* MMSYS errors */ +MMSYSERR_NOERROR, "Нет ошибки." +MMSYSERR_ERROR, "Неизвестная ошибка." +MMSYSERR_BADDEVICEID, "Используемый код устройства (device ID) выходит за допустимые пределы." +MMSYSERR_NOTENABLED, "Драйвер не был подключен." +MMSYSERR_ALLOCATED, "Указанное устройство уже используется. Подождите пока оно освободится, затем попробуйте еще раз." +MMSYSERR_INVALHANDLE, "Указанный идентификатор устройства (device handle) неверен." +MMSYSERR_NODRIVER, "В системе не установлен драйвер! \n" +MMSYSERR_NOMEM, "Не хватает памяти для задачи. Закройте одно или несколько приложений и попробуйте заново." +MMSYSERR_NOTSUPPORTED, "Эта функция не поддерживается. Используйте функцию Capabilities, чтобы определить функции и сообщения, которые поддерживает драйвер." +MMSYSERR_BADERRNUM, "Указанный код ошибки не определен в системе." +MMSYSERR_INVALFLAG, "Недопустимый флажок передан системной функции." +MMSYSERR_INVALPARAM, "Недопустимый параметр передан системной функции." + +/* WAVE errors */ +WAVERR_BADFORMAT, "Указанный формат не поддерживается или не может быть оттранслирован. Используйте функцию Capabilities, чтобы определить поддерживаемые форматы." +WAVERR_STILLPLAYING, "Невозможно произвести операцию, пока устройство в режиме воспроизведения. Сбросьте устройство, или подождите пока устройство не окончит воспроизведение." +WAVERR_UNPREPARED, "Заголовок wave не был подготовлен. Используйте функцию Prepare, чтобы подготовить заголовок и попробуйте заново." +WAVERR_SYNC, "Невозможно открыть устройство, не используя флаг WAVE_ALLOWSYNC. Используйте флаг и попробуйте заново." + +/* MIDI errors */ +MIDIERR_UNPREPARED, "Заголовок MIDI не был подготовлен. Используйте функцию Prepare, чтобы подготовить заголовок и попробуйте заново." +MIDIERR_STILLPLAYING, "Невозможно произвести операцию, пока устройство в режиме воспроизведения. Сбросьте устройство, или подождите пока устройство не окончит воспроизведение." +MIDIERR_NOMAP, "Карта (map) MIDI не найдена. Возможно, это ошибка драйвера, или файл MIDIMAP.CFG отсутствует или поврежден." +MIDIERR_NOTREADY, "Порт передает информацию в устройство. Подождите, пока информация будет передана и попробуйте заново." +MIDIERR_NODEVICE, "Текущие установки MIDI Mapper ссылаются на устройство MIDI, которое не установлено в системе. Используйте MIDI Mapper для редактирования установок." +MIDIERR_INVALIDSETUP, "Текущие установки MIDI повреждены. Скопируйте исходный файл MIDIMAP.CFG в директорию Windows SYSTEM, и попробуйте заново." + +/* MCI errors */ +MCIERR_INVALID_DEVICE_ID, "Недопустимый код устройства MCI. Используйте код, возвращенный при открытии устройства MCI." +MCIERR_UNRECOGNIZED_KEYWORD, "Драйвер не может определить указанный параметр команды." +MCIERR_UNRECOGNIZED_COMMAND, "Драйвер не может определить указанную команду." +MCIERR_HARDWARE, "Ошибка мультимедиа устройства. Убедитесь, что устройство работает нормально или свяжитесь с изготовителем устройства." +MCIERR_INVALID_DEVICE_NAME, "Указанное устройство не открыто или не опознано MCI." +MCIERR_OUT_OF_MEMORY, "Не хватает памяти для задачи. \nЗакройте одно или несколько приложений, чтобы освободить память и попробуйте заново." +MCIERR_DEVICE_OPEN, "Название устройства уже используется приложением как псевдоним. Используйте уникальное имя." +MCIERR_CANNOT_LOAD_DRIVER, "Неопределенная ошибка при загрузке указанного драйвера." +MCIERR_MISSING_COMMAND_STRING, "Команда не указана." +MCIERR_PARAM_OVERFLOW, "Возвращаемая строка слишком велика, чтобы поместиться в буфере. Увеличьте размер буфера." +MCIERR_MISSING_STRING_ARGUMENT, "Указанная команда требует строковый параметр." +MCIERR_BAD_INTEGER, "Указанное целое недопустимо для этой команды." +MCIERR_PARSER_INTERNAL, "Драйвер устройства возвратил недопустимый при возвращении тип. Свяжитесь с изготовителем драйвера для получения новой версии драйвера." +MCIERR_DRIVER_INTERNAL, "Ошибка драйвера устройства. Свяжитесь с изготовителем драйвера для получения новой версии драйвера." +MCIERR_MISSING_PARAMETER, "Указанная команда требует параметр." +MCIERR_UNSUPPORTED_FUNCTION, "Используемое вами устройство MCI не поддерживает указанную команду." +MCIERR_FILE_NOT_FOUND, "Невозможно найти указанный файл. Убедитесь в правильности пути и имени файла." +MCIERR_DEVICE_NOT_READY, "Драйвер устройства не готов." +MCIERR_INTERNAL, "Ошибка при инициализации MCI. Попробуйте перезапустить Windows." +MCIERR_DRIVER, "Ошибка в драйвере устройства. Драйвер закрыт, сообщение об ошибке недоступно." +MCIERR_CANNOT_USE_ALL, "Невозможно использовать 'all' в качестве имени устройства в указанной команде." +MCIERR_MULTIPLE, "Ошибки в нескольких устройствах. Укажите отдельно каждую команду и устройство, чтобы определить, какие устройства вызывали ошибки." +MCIERR_EXTENSION_NOT_FOUND, "Невозможно определить тип устройства по данному расширению файла." +MCIERR_OUTOFRANGE, "Указанный параметр выходит за допустимые пределы для указанной команды." +MCIERR_FLAGS_NOT_COMPATIBLE, "Указанные параметры нельзя использовать вместе." +MCIERR_FILE_NOT_SAVED, "Невозможно сохранить указанный файл. Убедитесь, что на диске достаточно места, или проверьте сетевое подключение." +MCIERR_DEVICE_TYPE_REQUIRED, "Невозможно найти указанное устройство. Убедитесь, что оно установлено, и что устройство указано правильно." +MCIERR_DEVICE_LOCKED, "Указанное устройство сейчас закрывается. Подождите несколько секунд и попробуйте заново." +MCIERR_DUPLICATE_ALIAS, "Название устройства уже используется приложением как псевдоним. Используйте уникальное имя." +MCIERR_BAD_CONSTANT, "Указанный параметр недопустим для этой команды." +MCIERR_MUST_USE_SHAREABLE, "Драйвер устройства уже используется. Для совместного доступа используйте параметр 'shareable' в каждой команде 'open'." +MCIERR_MISSING_DEVICE_NAME, "Указанная команда требует псевдоним, файл, драйвер, или имя устройства. Укажите его." +MCIERR_BAD_TIME_FORMAT, "Указанное значение в формате времени неверно. Обратитесь к документации MCI для выяснения допустимых форматов." +MCIERR_NO_CLOSING_QUOTE, "Закрывающая кавычка отсутствует в значении параметра. Поставьте ее ;-)" +MCIERR_DUPLICATE_FLAGS, "Параметр или значение указано дважды. Требуется указывать только один раз." +MCIERR_INVALID_FILE, "Указанный файл не может быть проигран на выбранном устройстве MCI. Файл может быть поврежден или имеет некорректный формат." +MCIERR_NULL_PARAMETER_BLOCK, "MCI был передан пустой блок параметров." +MCIERR_UNNAMED_RESOURCE, "Невозможно сохранить неназванный файл. Назовите его." +MCIERR_NEW_REQUIRES_ALIAS, "Вы должны указать псевдоним при использовании параметра 'new'." +MCIERR_NOTIFY_ON_AUTO_OPEN, "Невозможно использовать флаг 'notify' с устройствами, открытыми автоматически." +MCIERR_NO_ELEMENT_ALLOWED, "Невозможно использовать имя файла с указанным устройством." +MCIERR_NONAPPLICABLE_FUNCTION, "Невозможно исполнить команды в указанном порядке. Исправьте последовательность команд и попробуйте заново." +MCIERR_ILLEGAL_FOR_AUTO_OPEN, "Невозможно исполнить команду для устройства, открытого автоматически. Подождите пока устройство не будет закрыто и попробуйте заново." +MCIERR_FILENAME_REQUIRED, "Недопустимое имя файла. Убедитесь, что имя файла не длиннее 8 символов, за ним следует точка и расширение." +MCIERR_EXTRA_CHARACTERS, "Нельзя указывать символы после строки, заключенной в кавычки." +MCIERR_DEVICE_NOT_INSTALLED, "Указанное устройство не установлено в системе. Используйте Control Panel для установки драйвера." +MCIERR_GET_CD, "Нет доступа к указанному файлу или устройству МCI. Попробуйте перезапустить компьютер ;-)" +MCIERR_SET_CD, "Нет доступа к указанному файлу или устройству MCI, потому что приложение не может менять директории." +MCIERR_SET_DRIVE, "Нет доступа к указанному файлу или устройству MCI, потому что приложение не может менять диски." +MCIERR_DEVICE_LENGTH, "Имя драйвера или устройства должно быть короче 79 символов." +MCIERR_DEVICE_ORD_LENGTH, "Имя драйвера или устройства должно быть короче 69 символов." +MCIERR_NO_INTEGER, "Указанная команда требует параметр целого типа." +MCIERR_WAVE_OUTPUTSINUSE, "Все wave-устройства, которые могут воспроизводить файлы в текущем формате, заняты. Подождите пока освободится wave-устройство, и попробуйте заново." +MCIERR_WAVE_SETOUTPUTINUSE, "Невозможно использовать текущее устройство для воспроизведения, т.к. оно занято. Подождите, пока устройство освободится, и попробуйте заново." +MCIERR_WAVE_INPUTSINUSE, "Невозможно использовать текущее устройство для записи, т.к. оно занято. Подождите, пока устройство освободится, и попробуйте заново." +MCIERR_WAVE_SETINPUTINUSE, "Невозможно использовать текущее устройство для воспроизведения, т.к. оно занято. Подождите, пока устройство освободится, и попробуйте заново." +MCIERR_WAVE_OUTPUTUNSPECIFIED, "Может быть использовано любое устройство для проигрывания звука." +MCIERR_WAVE_INPUTUNSPECIFIED, "Может быть использовано любое устройство для записи звука." +MCIERR_WAVE_OUTPUTSUNSUITABLE, "Нет устройства для воспроизведения файлов в текущем формате. Используйте опцию Drivers для установки звукового устройства." +MCIERR_WAVE_SETOUTPUTUNSUITABLE,"Устройство, на которое вы проигрываете, не поддерживает формат текущего файла." +MCIERR_WAVE_INPUTSUNSUITABLE, "Нет устройства для записи файлов в текущем формате. Используйте опцию Drivers для установки звукового устройства." +MCIERR_WAVE_SETINPUTUNSUITABLE, "Устройство, с которого вы записываете, не может распознать текущий формат файла." +MCIERR_NO_WINDOW, "Нет окна для отображения." +MCIERR_CREATEWINDOW, "Невозможно создать или использовать окно." +MCIERR_FILE_READ, "Невозможно прочитать указанный файл. Убедитесь, что файл существует, или проверьте диск или сетевое подключение. " +MCIERR_FILE_WRITE, "Невозможно записать в указанный файл. Убедитесь, что на диске достаточно места, или проверьте сетевое подключение." +MCIERR_SEQ_DIV_INCOMPATIBLE, "Форматы времени ""song pointer"" и SMPTE взаимно исключаемые. Нельзя использовать их вместе." +MCIERR_SEQ_NOMIDIPRESENT, "В системе не установлены устройства MIDI. Используйте Drivers в Control Panel, чтобы установить драйвер MIDI." +MCIERR_SEQ_PORT_INUSE, "Указанный порт MIDI уже используется. Подождите, пока он освободится, и попробуйте заново." +MCIERR_SEQ_PORT_MAPNODEVICE, "Текущие установки MIDI Mapper ссылаются на не установленное в системе устройство MIDI. Используйте MIDI Mapper в Control Panel, чтобы отредактировать установки." +MCIERR_SEQ_PORT_MISCERROR, "Ошибка указанного порта." +MCIERR_SEQ_PORT_NONEXISTENT, "В системе не установлены устройства MIDI. Используйте Drivers в Control Panel, чтобы установить драйвер MIDI." +MCIERR_SEQ_PORTUNSPECIFIED, "В системе не указан текущий порт MIDI." +MCIERR_SEQ_TIMER, "Все таймеры мультимедиа используются другими приложениями. Закройте одно из этих приложений и попробуйте заново." + +END + +/* translation by Zahar Hodoley (mail: zaharh@mail.ru) */ diff --git a/reactos/lib/winmm/winmm_Si.rc b/reactos/lib/winmm/winmm_Si.rc new file mode 100644 index 00000000000..5010fd54d4d --- /dev/null +++ b/reactos/lib/winmm/winmm_Si.rc @@ -0,0 +1,127 @@ +/* + * Copyright 2002-2003 Rok Mandeljc + * + * 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 + * + */ + +STRINGTABLE LANGUAGE LANG_SLOVENIAN, SUBLANG_DEFAULT +BEGIN + +/* MMSYS errors */ +MMSYSERR_NOERROR, "Navedeni ukaz je bil izveden." +MMSYSERR_ERROR, "Neznana zunanja napaka." +MMSYSERR_BADDEVICEID, "Uporabljena identifikacijska oznaka naprave je zunaj dopustnega obsega za vaљ sistem." +MMSYSERR_NOTENABLED, "Gonilnik ni bil omogoиen." +MMSYSERR_ALLOCATED, "Navedena naprava je ћe v uporabi. Poиakajte, da bo spet prosta, in poskusite znova." +MMSYSERR_INVALHANDLE, "Navedena koda za dostop do naprave ni veljavna." +MMSYSERR_NODRIVER, "Noben gonilnik ni nameљиen !\n" +MMSYSERR_NOMEM, "Za to opravilo ni na voljo dovolj pomnilnika. Konиajte enega ali veи programov in poskusite znova." +MMSYSERR_NOTSUPPORTED, "Ta funkcija ni podprta. Иe ћelite ugotoviti, katere funkcije podpira gonilnik, uporabite moћnost 'Funkcije'." +MMSYSERR_BADERRNUM, "Navedena je bila љtevilka napake, ki v sistemu ni definirana." +MMSYSERR_INVALFLAG, "Sistemska funkcija je prejela neveljavno zastavico." +MMSYSERR_INVALPARAM, "Sistemska funkcija je prejela neveljaven parameter." + +/* WAVE errors */ +WAVERR_BADFORMAT, "Navedena oblika zapisa ni podprta ali pa je ni mogoиe prevesti. Иe ћelite ugotoviti, katere oblike so podprte, uporabite moћnost 'Funkcije'." +WAVERR_STILLPLAYING, "Predvajanje љe traja. Ponastavite napravo ali pa poиakajte do konca predvajanja." +WAVERR_UNPREPARED, "Glava podatkov vrste wave ni bila pripravljena. Pripravite glavo, tako da uporabite funkcijo 'Pripravi' (Prepare), in poskusite znova." +WAVERR_SYNC, "Brez zastavice WAVE_ALLOWSYNC ni mogoиe odpreti naprave. Uporabite jo in poskusite znova." + +/* MIDI errors */ +MIDIERR_UNPREPARED, "MIDI glava ni bila pripravljena. Pripravite glavo, tako da uporabite funkcijo 'Pripravi' (Prepare), in poskusite znova." +MIDIERR_STILLPLAYING, "Predvajanje љe traja. Ponastavite napravo ali pa poиakajte do konca predvajanja." +MIDIERR_NOMAP, "Razporeditve MIDI ni mogo1e najti. To je lahko posledica teћav z gonilnikom, ali pa manjkajoи ali poљkodovane datoteke MIDIMAP.CFG." +MIDIERR_NOTREADY, "Prek vrat poteka prenos podatkov do naprave. Poиakajte, da se prenos konиa in poskusite znova." +MIDIERR_NODEVICE, "Trenutna nastavitev MIDI se sklicuje na MIDI napravo, ki ni prisotna. Uporabite MIDI Mapper in spremenite nastavitve." +MIDIERR_INVALIDSETUP, "Trenutna nastavitev MIDI je poљodovana. Namestite originalno datoteko MIDIMAP.CFG v sistemsko mapo Windows (System) in poskusite znova." + +/* MCI errors */ +MCIERR_INVALID_DEVICE_ID, "Neveljavna identifikacijska oznaka MCI naprave. Uporabite oznako, ki jo vrne odpiranje MCI naprave." +MCIERR_UNRECOGNIZED_KEYWORD, "Naveden parameter ukaza ni definiran v naboru MCI ukazov." +MCIERR_UNRECOGNIZED_COMMAND, "Naveden ukaz ni veljaven MCI ukaz." +MCIERR_HARDWARE, "S predstavnostno napravo so teћave. Preverite, ali naprava deluje pravilno ali pa se posvetujte z izdelovalcem." +MCIERR_INVALID_DEVICE_NAME, "To ni registrirana MCI naprava." +MCIERR_OUT_OF_MEMORY, "Za to opravilo ni na voljo dovolj pomnilnika. \nKonиajte enega ali veи programov in poskusite znova." +MCIERR_DEVICE_OPEN, "Ta program ћe uporablja ta vzdevek. Namesto imena naprave uporabite љe neuporabljen vzdevek." +MCIERR_CANNOT_LOAD_DRIVER, "Naprave ni bilo mogoиe naloћiti. Preverite, ali je gonilnik pravilno nameљиen." +MCIERR_MISSING_COMMAND_STRING, "Ukazni niz je prazen." +MCIERR_PARAM_OVERFLOW, "Izhodni niz je bil prevelik, da bi ga bilo mogoиe shraniti v povratni medpomnilnik. Poveиajte medpomnilnik." +MCIERR_MISSING_STRING_ARGUMENT, "Navedeni ukaz zahteva parameter (niz znakov). Vnesite ga." +MCIERR_BAD_INTEGER, "Vneseno celo љtevilo za ta ukaz ni veljavno. Vnesite љtevilo." +MCIERR_PARSER_INTERNAL, "Gonilnik za napravo je vrnil neveljavno vrsto vrednosti. Od izdelovalca naprave poskusite dobiti nov gonilnik." +MCIERR_DRIVER_INTERNAL, "Z gonilnikom za napravo so teћave. Od izdelovalca naprave poskusite dobiti nov gonilnik." +MCIERR_MISSING_PARAMETER, "V navedenem ukazu manjka parameter. Vnesite ga." +MCIERR_UNSUPPORTED_FUNCTION, "MCI naprava, ki jo uporabljate, ne podpira navedenega ukaza." +MCIERR_FILE_NOT_FOUND, "Navedene datoteke ni mogoиe najti. Preverite, ali ste pravilno vnesli ime in pot do datoteke." +MCIERR_DEVICE_NOT_READY, "Gonilnik za napravo ni pripravljen. Malo poиakajte in nato poskusite znova." +MCIERR_INTERNAL, "Pri inicializaciji MCI naprave je priљlo do teћav. Znova zaћenite Windows." +MCIERR_DRIVER, "Zaradi napake, znaиilne za gonilnik, je bil gonilnik zaprt. Ponovite ukaz." +MCIERR_CANNOT_USE_ALL, "V tem ukazu uporabite ime toиno doloиene naprave." +MCIERR_MULTIPLE, "V veи napravah je priљlo do napak. Loиeno vnesite vsak ukaz in vsako napravo. Tako boste lahko ugotovili, katere naprave povzroиajo napake." +MCIERR_EXTENSION_NOT_FOUND, "Iz pripone datoteke ni mogoиe ugotoviti vrste zahtevane naprave." +MCIERR_OUTOFRANGE, "Parameter je zunaj dovoljenega obsega za naveden ukaz." +MCIERR_FLAGS_NOT_COMPATIBLE, "Navedenih parametrov ne smete uporabiti hkrati." +MCIERR_FILE_NOT_SAVED, "Navedene datoteke ni mogoиe shraniti. Preverite, ali je na disku dovolj prostora oz. ali je vaљ raиunalnik љe povezan z omreћjem." +MCIERR_DEVICE_TYPE_REQUIRED, "Navedene naprave ni mogoиe najti. Preverite, ali je naprava nameљиena oz. ali je bilo njeno ime pravilno navedeno." +MCIERR_DEVICE_LOCKED, "Poteka zapiranje navedene naprave. Malo poиakajte in poskusite znova." +MCIERR_DUPLICATE_ALIAS, "Ta program ћe uporablja navedeni vzdevek. Uporabite љe neuporabljen vzdevek." +MCIERR_BAD_CONSTANT, "Uporabljena konstanta v tem ukazu ni veljavna." +MCIERR_MUST_USE_SHAREABLE, "Gonilnik naprave je ћe v uporabi. Иe ga ћelite dati v skupno rabo, z vsakim ukazom 'open' uporabite parameter 'shareable'." +MCIERR_MISSING_DEVICE_NAME, "Navedeni ukaz zahteva vzdevek, datoteko, gonilnik ali ime naprave. Vnesite ustrezno ime." +MCIERR_BAD_TIME_FORMAT, "Navedena vrednost za obliko zapisa иasa ni veljavna. Veljavne oblike poiљиite v dokumentaciji MCI naprave." +MCIERR_NO_CLOSING_QUOTE, "V vrednosti za parameter manjka zakljuиni dvojni narekovaj. Vnesite ga." +MCIERR_DUPLICATE_FLAGS, "Parameter ali vrednost ste navedli dvakrat. Navedite ga samo enkrat." +MCIERR_INVALID_FILE, "Te datoteke ne morete predvajati z navedeno MCI napravo. Datoteka je morda poљkodovana ali pa ima napaиno obliko zapisa." +MCIERR_NULL_PARAMETER_BLOCK, "MCI napravi je bil predan 'null parameter block'." +MCIERR_UNNAMED_RESOURCE, "Datoteke brez imena ni mogoиe shraniti. Vnesite ime." +MCIERR_NEW_REQUIRES_ALIAS, "Ko uporabljate parameter 'new', morate navesti vzdevek." +MCIERR_NOTIFY_ON_AUTO_OPEN, "Zastavice 'notify' ni mogoиe uporabiti pri napravah, ki se samodejno odpirajo." +MCIERR_NO_ELEMENT_ALLOWED, "V povezavi z navedeno napravo ne morete uporabiti imena datoteke." +MCIERR_NONAPPLICABLE_FUNCTION, "Ukazov v navedenem zaporedju ni mogoиe izvesti. Spremenite zaporedje in poskusite znova." +MCIERR_ILLEGAL_FOR_AUTO_OPEN, "Ukaza ni mogoиe izvesti v povezavi z napravo, ki se samodejno odpre. Poиakajte, da se naprava zapre, in poskusite znova." +MCIERR_FILENAME_REQUIRED, "Ime datoteke ni veljavno." +MCIERR_EXTRA_CHARACTERS, "Za nizom znakov, ki je obdan z narekovaji, ni mogoиe zapisati dodatnih znakov." +MCIERR_DEVICE_NOT_INSTALLED, "Naprava ni nameљиena. Иe ћelite namestiti nov gonilnik, na nadzorni ploљиi dvokliknite ikono 'Dodajanje strojne opreme'." +MCIERR_GET_CD, "Dostop do navedene datoteke ali MCI naprave ni mogoи. Zamenjajte imenik ali pa znova zaћenite raиunalnik." +MCIERR_SET_CD, "Dostop do navedene datoteke ali MCI naprave ni mogoи, ker program ne more zamenjati imenika." +MCIERR_SET_DRIVE, "Dostop do navedene datoteke ali MCI naprave ni mogoи, ker program ne more zamenjati pogona." +MCIERR_DEVICE_LENGTH, "Navedite ime za napravo ali gonilnik, ki je krajљe od 79 znakov." +MCIERR_DEVICE_ORD_LENGTH, "Navedite ime za napravo ali gonilnik, ki je krajљe od 69 znakov." +MCIERR_NO_INTEGER, "Navedeni ukaz zahteva љtevilиni parameter (npr. 'play to 10'). Vnesite ga." +MCIERR_WAVE_OUTPUTSINUSE, "Vse naprave, ki lahko predvajajo datoteke v obliki wave, so v uporabi. Poskusite znova, ko bo katera od njih na voljo." +MCIERR_WAVE_SETOUTPUTINUSE, "Trenutna wave naprava je v uporabi. Poиakajte, da bo prosta, in poskusite znova." +MCIERR_WAVE_INPUTSINUSE, "Vse naprave, ki lahko snemajo datoteke v obliki wave, so v uporabi. Poskusite znova, ko bo katera od njih na voljo." +MCIERR_WAVE_SETINPUTINUSE, "Trenutna wave naprava je v uporabi. Poиakajte, da bo prosta, in poskusite znova." +MCIERR_WAVE_OUTPUTUNSPECIFIED, "Predvajalna naprava je v uporabi. Poskusite znova, ko bo predvajanje konиano." +MCIERR_WAVE_INPUTUNSPECIFIED, "Snemalna naprava je v uporabi. Poskusite znova, ko bo snemanje konиano." +MCIERR_WAVE_OUTPUTSUNSUITABLE, "Nameљиena ni nobena naprava za wave, ki bi lahko predvajala datoteke v trenutni obliki." +MCIERR_WAVE_SETOUTPUTUNSUITABLE,"Naprava ne prepozna trenutne oblike zapisa datoteke. Izberite drugo napravo in poskusite znova." +MCIERR_WAVE_INPUTSUNSUITABLE, "Nameљиena ni nobena naprava za wave, ki bi lahko snemala datoteke v trenutni obliki." +MCIERR_WAVE_SETINPUTUNSUITABLE, "Naprava ne prepozna trenutne oblike zapisa datoteke. Izberite drugo napravo in poskusite znova." +MCIERR_NO_WINDOW, "Ni okna za prikaz." +MCIERR_CREATEWINDOW, "Okna ni bilo mogoиe ustvariti ali uporabiti." +MCIERR_FILE_READ, "Te datoteke ni mogoиe brati. Preverite, ali ni bila morda izbrisana. Preverite tudi svoj disk in omreћne povezave." +MCIERR_FILE_WRITE, "V navedeno datoteko ni mogoиe pisati. Preverite, ali je na disku љe dovolj prostora oz. ali je vaљ raиunalnik љe povezan z omreћjem." +MCIERR_SEQ_DIV_INCOMPATIBLE, "Hkrati ni mogoиe uporabiti oblik zapisa иasa 'song-pointer' in SMPTE." +MCIERR_SEQ_NOMIDIPRESENT, "V sistemu ni nameљиena nobena MIDI naprava. Za namestitev MIDI gonilnika uporabite moћnost 'Drivers' na Nadzorni ploљиi." +MCIERR_SEQ_PORT_INUSE, "Navedena MIDI naprava je ћe v uporabi. Poиakajte, da bo prosta, in poskusite znova." +MCIERR_SEQ_PORT_MAPNODEVICE, "Trenutna nastavitev MIDI se sklicuje na napravo, ki ni nameљиena. Uporabite moћnost 'MIDI Mapper' na Nadzorni ploљиi in spremenite nastavitev." +MCIERR_SEQ_PORT_MISCERROR, "Na navedenih vratih je priљlo do napake." +MCIERR_SEQ_PORT_NONEXISTENT, "Ta naprava ni nameљиena. Иe ћelite namestiti nov gonilnik, na nadzorni ploљиi dvokliknite ikono 'Dodajanje strojne opreme'." +MCIERR_SEQ_PORTUNSPECIFIED, "Zahtevana MIDI vrata niso nameљиena." +MCIERR_SEQ_TIMER, "Vsi veиpredstavnostni љtevci so zasedeni. Zaprite eno od aplikacij in poskusite znova." + +END diff --git a/reactos/lib/winmm/winmm_Sk.rc b/reactos/lib/winmm/winmm_Sk.rc new file mode 100644 index 00000000000..65441fb1828 --- /dev/null +++ b/reactos/lib/winmm/winmm_Sk.rc @@ -0,0 +1,126 @@ +/* + * Copyright 2000 Peter Ivanyi + * + * 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 + */ + +STRINGTABLE LANGUAGE LANG_SLOVAK, SUBLANG_NEUTRAL +BEGIN + +/* MMSYS errors */ +MMSYSERR_NOERROR, "Љpecifikovanэ prнkaz bol vykonanэ." +MMSYSERR_ERROR, "Nedefinovanб externб chyba." +MMSYSERR_BADDEVICEID, "A device ID has been used that is out of range for your system." +MMSYSERR_NOTENABLED, "The driver was not enabled." +MMSYSERR_ALLOCATED, "The specified device is already in use. Wait until it is free, and then try again." +MMSYSERR_INVALHANDLE, "The specified device handle is invalid." +MMSYSERR_NODRIVER, "There is no driver installed on your system !\n" +MMSYSERR_NOMEM, "Not enough memory available for this task. Quit one or more applications to increase available memory, and then try again." +MMSYSERR_NOTSUPPORTED, "This function is not supported. Use the Capabilities function to determine which functions and messages the driver supports." +MMSYSERR_BADERRNUM, "An error number was specified that is not defined in the system." +MMSYSERR_INVALFLAG, "An invalid flag was passed to a system function." +MMSYSERR_INVALPARAM, "An invalid parameter was passed to a system function." + +/* WAVE errors */ +WAVERR_BADFORMAT, "The specified format is not supported or cannot be translated. Use the Capabilities function to determine the supported formats" +WAVERR_STILLPLAYING, "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing." +WAVERR_UNPREPARED, "The wave header was not prepared. Use the Prepare function to prepare the header, and then try again." +WAVERR_SYNC, "Cannot open the device without using the WAVE_ALLOWSYNC flag. Use the flag, and then try again." + +/* MIDI errors */ +MIDIERR_UNPREPARED, "The MIDI header was not prepared. Use the Prepare function to prepare the header, and then try again." +MIDIERR_STILLPLAYING, "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing." +MIDIERR_NOMAP, "A MIDI map was not found. There may be a problem with the driver, or the MIDIMAP.CFG file may be corrupt or missing." +MIDIERR_NOTREADY, "The port is transmitting data to the device. Wait until the data has been transmitted, and then try again." +MIDIERR_NODEVICE, "The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use MIDI Mapper to edit the setup." +MIDIERR_INVALIDSETUP, "The current MIDI setup is damaged. Copy the original MIDIMAP.CFG file to the Windows SYSTEM directory, and then try again." + +/* MCI errors */ +MCIERR_INVALID_DEVICE_ID, "Invalid MCI device ID. Use the ID returned when opening the MCI device." +MCIERR_UNRECOGNIZED_KEYWORD, "The driver cannot recognize the specified command parameter." +MCIERR_UNRECOGNIZED_COMMAND, "The driver cannot recognize the specified command." +MCIERR_HARDWARE, "There is a problem with your media device. Make sure it is working correctly or contact the device manufacturer." +MCIERR_INVALID_DEVICE_NAME, "The specified device is not open or is not recognized by MCI." +MCIERR_OUT_OF_MEMORY, "Not enough memory available for this task. \nQuit one or more applications to increase available memory, and then try again." +MCIERR_DEVICE_OPEN, "The device name is already being used as an alias by this application. Use a unique alias." +MCIERR_CANNOT_LOAD_DRIVER, "There is an undetectable problem in loading the specified device driver." +MCIERR_MISSING_COMMAND_STRING, "Nebol љpecifikovanэ ћiadny prнkaz." +MCIERR_PARAM_OVERFLOW, "The output string was to large to fit in the return buffer. Increase the size of the buffer." +MCIERR_MISSING_STRING_ARGUMENT, "The specified command requires a character-string parameter. Please provide one." +MCIERR_BAD_INTEGER, "The specified integer is invalid for this command." +MCIERR_PARSER_INTERNAL, "The device driver returned an invalid return type. Check with the device manufacturer about obtaining a new driver." +MCIERR_DRIVER_INTERNAL, "There is a problem with the device driver. Check with the device manufacturer about obtaining a new driver." +MCIERR_MISSING_PARAMETER, "The specified command requires a parameter. Please supply one." +MCIERR_UNSUPPORTED_FUNCTION, "The MCI device you are using does not support the specified command." +MCIERR_FILE_NOT_FOUND, "Cannot find the specified file. Make sure the path and filename are correct." +MCIERR_DEVICE_NOT_READY, "Ovlбdaи zariadenia nie je pripravenэ." +MCIERR_INTERNAL, "A problem occurred in initializing MCI. Try restarting Windows." +MCIERR_DRIVER, "There is a problem with the device driver. The driver has closed. Cannot access error." +MCIERR_CANNOT_USE_ALL, "Cannot use 'all' as the device name with the specified command." +MCIERR_MULTIPLE, "Errors occurred in more than one device. Specify each command and device separately to determine which devices caused the error" +MCIERR_EXTENSION_NOT_FOUND, "Cannot determine the device type from the given filename extension." +MCIERR_OUTOFRANGE, "The specified parameter is out of range for the specified command." +MCIERR_FLAGS_NOT_COMPATIBLE, "The specified parameters cannot be used together." +MCIERR_FILE_NOT_SAVED, "Cannot save the specified file. Make sure you have enough disk space or are still connected to the network." +MCIERR_DEVICE_TYPE_REQUIRED, "Cannot find the specified device. Make sure it is installed or that the device name is spelled correctly." +MCIERR_DEVICE_LOCKED, "The specified device is now being closed. Wait a few seconds, and then try again." +MCIERR_DUPLICATE_ALIAS, "The specified alias is already being used in this application. Use a unique alias." +MCIERR_BAD_CONSTANT, "The specified parameter is invalid for this command." +MCIERR_MUST_USE_SHAREABLE, "The device driver is already in use. To share it, use the 'shareable' parameter with each 'open' command." +MCIERR_MISSING_DEVICE_NAME, "The specified command requires an alias, file, driver, or device name. Please supply one." +MCIERR_BAD_TIME_FORMAT, "The specified value for the time format is invalid. Refer to the MCI documentation for valid formats." +MCIERR_NO_CLOSING_QUOTE, "A closing double-quotation mark is missing from the parameter value. Please supply one." +MCIERR_DUPLICATE_FLAGS, "A parameter or value was specified twice. Only specify it once." +MCIERR_INVALID_FILE, "The specified file cannot be played on the specified MCI device. The file may be corrupt, or not in the correct format." +MCIERR_NULL_PARAMETER_BLOCK, "A null parameter block was passed to MCI." +MCIERR_UNNAMED_RESOURCE, "Cannot save an unnamed file. Supply a filename." +MCIERR_NEW_REQUIRES_ALIAS, "You must specify an alias when using the 'new' parameter." +MCIERR_NOTIFY_ON_AUTO_OPEN, "Cannot use the 'notify' flag with auto-opened devices." +MCIERR_NO_ELEMENT_ALLOWED, "Cannot use a filename with the specified device." +MCIERR_NONAPPLICABLE_FUNCTION, "Cannot carry out the commands in the order specified. Correct the command sequence, and then try again." +MCIERR_ILLEGAL_FOR_AUTO_OPEN, "Cannot carry out the specified command on an auto-opened device. Wait until the device is closed, and then try again." +MCIERR_FILENAME_REQUIRED, "The filename is invalid. Make sure the filename is not longer than 8 characters, followed by a period and an extension." +MCIERR_EXTRA_CHARACTERS, "Cannot specify extra characters after a string enclosed in quotation marks." +MCIERR_DEVICE_NOT_INSTALLED, "The specified device is not installed on the system. Use the Drivers option in Control Panel to install the device." +MCIERR_GET_CD, "Cannot access the specified file or MCI device. Try changing directories or restarting your computer." +MCIERR_SET_CD, "Cannot access the specified file or MCI device because the application cannot change directories." +MCIERR_SET_DRIVE, "Cannot access specified file or MCI device because the application cannot change drives." +MCIERR_DEVICE_LENGTH, "Specify a device or driver name that is less than 79 characters." +MCIERR_DEVICE_ORD_LENGTH, "Specify a device or driver name that is less than 69 characters." +MCIERR_NO_INTEGER, "The specified command requires an integer parameter. Please provide one." +MCIERR_WAVE_OUTPUTSINUSE, "All wave devices that can play files in the current format are in use. Wait until a wave device is free, and then try again." +MCIERR_WAVE_SETOUTPUTINUSE, "Cannot set the current wave device for play back because it is in use. Wait until the device is free, and then try again." +MCIERR_WAVE_INPUTSINUSE, "All wave devices that can record files in the current format are in use. Wait until a wave device is free, and then try again." +MCIERR_WAVE_SETINPUTINUSE, "Cannot set the current wave device for recording because it is in use. Wait until the device is free, and then try again." +MCIERR_WAVE_OUTPUTUNSPECIFIED, "Any compatible waveform playback device may be used." +MCIERR_WAVE_INPUTUNSPECIFIED, "Any compatible waveform recording device may be used." +MCIERR_WAVE_OUTPUTSUNSUITABLE, "No wave device that can play files in the current format is installed. Use the Drivers option to install the wave device." +MCIERR_WAVE_SETOUTPUTUNSUITABLE,"The device you are trying to play to cannot recognize the current file format." +MCIERR_WAVE_INPUTSUNSUITABLE, "No wave device that can record files in the current format is installed. Use the Drivers option to install the wave device." +MCIERR_WAVE_SETINPUTUNSUITABLE, "The device you are trying to record from cannot recognize the current file format." +MCIERR_NO_WINDOW, "There is no display window." +MCIERR_CREATEWINDOW, "Nemфћem vytvoriќ alebo pouћiќ okno." +MCIERR_FILE_READ, "Cannot read the specified file. Make sure the file is still present, or check your disk or network connection." +MCIERR_FILE_WRITE, "Cannot write to the specified file. Make sure you have enough disk space or are still connected to the network." +MCIERR_SEQ_DIV_INCOMPATIBLE, "The time formats of the ""song pointer"" and SMPTE are mutually exclusive. You can't use them together." +MCIERR_SEQ_NOMIDIPRESENT, "The system has no installed MIDI devices. Use the Drivers option from the Control Panel to install a MIDI driver." +MCIERR_SEQ_PORT_INUSE, "The specified MIDI port is already in use. Wait until it is free; the try again." +MCIERR_SEQ_PORT_MAPNODEVICE, "The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use the MIDI Mapper option from the Control Panel to edit the setup." +MCIERR_SEQ_PORT_MISCERROR, "An error occurred with the specified port." +MCIERR_SEQ_PORT_NONEXISTENT, "The specified MIDI device is not installed on the system. Use the Drivers option from the Control Panel to install a MIDI device." +MCIERR_SEQ_PORTUNSPECIFIED, "The system doesnot have a current MIDI port specified." +MCIERR_SEQ_TIMER, "All multimedia timers are being used by other applications. Quit one of these applications; then, try again." + +END diff --git a/reactos/lib/winmm/winmm_res.rc b/reactos/lib/winmm/winmm_res.rc new file mode 100644 index 00000000000..bd0b37dea30 --- /dev/null +++ b/reactos/lib/winmm/winmm_res.rc @@ -0,0 +1,876 @@ +/* Multimedia resources (MMSYSTEM.DLL & WINMM.DLL) + * + * Copyright (c) 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 + * + * Note: Win 9x (and of course Win 3.x) store their resources in MMSYSTEM.DLL + * Wine stores all resources in WINMM.DLL (as NT does) + * This shall be transparent to most apps (unless some look directly in + * MMSYSTEM...) + */ + +#include "windef.h" +#include "winbase.h" +#include "mmddk.h" +#include "winnls.h" + +/* Add your language specific defines here */ +#include "winmm_Cs.rc" +#include "winmm_De.rc" +#include "winmm_En.rc" +#include "winmm_Es.rc" +#include "winmm_Fr.rc" +#include "winmm_It.rc" +/* #include "winmm_Ja.rc" */ /* Gives error during ReactOS build */ +#include "winmm_Nl.rc" +#include "winmm_Pt.rc" +#include "winmm_Ru.rc" +#include "winmm_Si.rc" +#include "winmm_Sk.rc" + +/* do not add NLS specific stuff below that line */ + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL + +CORE RCDATA +BEGIN +"open\0", 0x00000803L, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"type\0", 0x00002000L, MCI_STRING, +"element\0", 0x00000200L, MCI_STRING, +"alias\0", 0x00000400L, MCI_STRING, +"shareable\0", 0x00000100L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"close\0", 0x00000804L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"play\0", 0x00000806L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"from\0", 0x00000004L, MCI_INTEGER, +"to\0", 0x00000008L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_COMMAND, +"record\0", 0x0000080fL, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"from\0", 0x00000004L, MCI_INTEGER, +"to\0", 0x00000008L, MCI_INTEGER, +"insert\0", 0x00000100L, MCI_FLAG, +"overwrite\0", 0x00000200L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"seek\0", 0x00000807L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"to start\0", 0x00000100L, MCI_FLAG, +"to end\0", 0x00000200L, MCI_FLAG, +"to\0", 0x00000008L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_COMMAND, +"stop\0", 0x00000808L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"pause\0", 0x00000809L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"status\0", 0x00000814L, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_CONSTANT, +"position\0", 0x00000002L, MCI_INTEGER, +"length\0", 0x00000001L, MCI_INTEGER, +"number of tracks\0", 0x00000003L, MCI_INTEGER, +"ready\0", 0x00000007L, MCI_INTEGER, +"mode\0", 0x00000004L, MCI_INTEGER, +"time format\0", 0x00000006L, MCI_INTEGER, +"current track\0", 0x00000008L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"track\0", 0x00000010L, MCI_INTEGER, +"start\0", 0x00000200L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"capability\0", 0x0000080bL, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_CONSTANT, +"can record\0", 0x00000001L, MCI_INTEGER, +"has audio\0", 0x00000002L, MCI_INTEGER, +"has video\0", 0x00000003L, MCI_INTEGER, +"uses files\0", 0x00000005L, MCI_INTEGER, +"compound device\0", 0x00000006L, MCI_INTEGER, +"device type\0", 0x00000004L, MCI_INTEGER, +"can eject\0", 0x00000007L, MCI_INTEGER, +"can play\0", 0x00000008L, MCI_INTEGER, +"can save\0", 0x00000009L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"\0", 0x00000000L, MCI_END_COMMAND, +"info\0", 0x0000080aL, MCI_COMMAND_HEAD, +"\0", 0x00000001L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"product\0", 0x00000100L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"set\0", 0x0000080dL, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"time format\0", 0x00000400L, MCI_CONSTANT, +"milliseconds\0", 0x00000000L, MCI_INTEGER, +"ms\0", 0x00000000L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"door open\0", 0x00000100L, MCI_FLAG, +"door closed\0", 0x00000200L, MCI_FLAG, +"audio\0", 0x00000800L, MCI_CONSTANT, +"all\0", 0x00000000L, MCI_INTEGER, +"left\0", 0x00000001L, MCI_INTEGER, +"right\0", 0x00000002L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"video\0", 0x00001000L, MCI_FLAG, +"on\0", 0x00002000L, MCI_FLAG, +"off\0", 0x00004000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"sysinfo\0", 0x00000810L, MCI_COMMAND_HEAD, +"\0", 0x00000001L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"quantity\0", 0x00000100L, MCI_FLAG, +"open\0", 0x00000200L, MCI_FLAG, +"installname\0", 0x00000800L, MCI_FLAG, +"name\0", 0x00000400L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_COMMAND, +"break\0", 0x00000811L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"on\0", 0x00000100L, MCI_INTEGER, +"off\0", 0x00000400L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"sound\0", 0x00000812L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"save\0", 0x00000813L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_STRING, +"\0", 0x00000000L, MCI_END_COMMAND, +"load\0", 0x00000850L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_STRING, +"\0", 0x00000000L, MCI_END_COMMAND, +"resume\0", 0x00000855L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"\0", 0x00000000L, MCI_END_COMMAND_LIST +END + +VIDEODISC RCDATA +BEGIN +"play\0", 0x00000806L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"from\0", 0x00000004L, MCI_INTEGER, +"to\0", 0x00000008L, MCI_INTEGER, +"fast\0", 0x00020000L, MCI_FLAG, +"slow\0", 0x00100000L, MCI_FLAG, +"speed\0", 0x00040000L, MCI_INTEGER, +"reverse\0", 0x00010000L, MCI_FLAG, +"scan\0", 0x00080000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"seek\0", 0x00000807L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"reverse\0", 0x00010000L, MCI_FLAG, +"to start\0", 0x00000100L, MCI_FLAG, +"to end\0", 0x00000200L, MCI_FLAG, +"to\0", 0x00000008L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_COMMAND, +"spin\0", 0x0000080cL, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"up\0", 0x00010000L, MCI_FLAG, +"down\0", 0x00020000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"step\0", 0x0000080eL, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"reverse\0", 0x00020000L, MCI_FLAG, +"by\0", 0x00010000L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_COMMAND, +"set\0", 0x0000080dL, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"time format\0", 0x00000400L, MCI_CONSTANT, +"milliseconds\0", 0x00000000L, MCI_INTEGER, +"ms\0", 0x00000000L, MCI_INTEGER, +"frames\0", 0x00000003L, MCI_INTEGER, +"hms\0", 0x00000001L, MCI_INTEGER, +"track\0", 0x00004001L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"door open\0", 0x00000100L, MCI_FLAG, +"door closed\0", 0x00000200L, MCI_FLAG, +"audio\0", 0x00000800L, MCI_CONSTANT, +"all\0", 0x00000000L, MCI_INTEGER, +"left\0", 0x00000001L, MCI_INTEGER, +"right\0", 0x00000002L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"video\0", 0x00001000L, MCI_FLAG, +"on\0", 0x00002000L, MCI_FLAG, +"off\0", 0x00004000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"status\0", 0x00000814L, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_CONSTANT, +"position\0", 0x00000002L, MCI_INTEGER, +"length\0", 0x00000001L, MCI_INTEGER, +"number of tracks\0", 0x00000003L, MCI_INTEGER, +"mode\0", 0x00000004L, MCI_INTEGER, +"media present\0", 0x00000005L, MCI_INTEGER, +"speed\0", 0x00004002L, MCI_INTEGER, +"forward\0", 0x00004003L, MCI_INTEGER, +"media type\0", 0x00004004L, MCI_INTEGER, +"ready\0", 0x00000007L, MCI_INTEGER, +"side\0", 0x00004005L, MCI_INTEGER, +"disc size\0", 0x00004006L, MCI_INTEGER, +"time format\0", 0x00000006L, MCI_INTEGER, +"current track\0", 0x00000008L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"track\0", 0x00000010L, MCI_INTEGER, +"start\0", 0x00000200L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"capability\0", 0x0000080bL, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"clv\0", 0x00010000L, MCI_FLAG, +"cav\0", 0x00020000L, MCI_FLAG, +"\0", 0x00000100L, MCI_CONSTANT, +"can record\0", 0x00000001L, MCI_INTEGER, +"has audio\0", 0x00000002L, MCI_INTEGER, +"has video\0", 0x00000003L, MCI_INTEGER, +"device type\0", 0x00000004L, MCI_INTEGER, +"uses files\0", 0x00000005L, MCI_INTEGER, +"compound device\0", 0x00000006L, MCI_INTEGER, +"can eject\0", 0x00000007L, MCI_INTEGER, +"can reverse\0", 0x00004002L, MCI_INTEGER, +"can play\0", 0x00000008L, MCI_INTEGER, +"can save\0", 0x00000009L, MCI_INTEGER, +"fast play rate\0", 0x00004003L, MCI_INTEGER, +"slow play rate\0", 0x00004004L, MCI_INTEGER, +"normal play rate\0", 0x00004005L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"\0", 0x00000000L, MCI_END_COMMAND, +"escape\0", 0x00000805L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_STRING, +"\0", 0x00000000L, MCI_END_COMMAND, +"info\0", 0x0000080aL, MCI_COMMAND_HEAD, +"\0", 0x00000001L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"product\0", 0x00000100L, MCI_FLAG, +"identity\0", 0x00000800L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"\0", 0x00000000L, MCI_END_COMMAND_LIST +END + +WAVEAUDIO RCDATA +BEGIN +"open\0", 0x00000803L, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"type\0", 0x00002000L, MCI_STRING, +"element\0", 0x00000200L, MCI_STRING, +"alias\0", 0x00000400L, MCI_STRING, +"shareable\0", 0x00000100L, MCI_FLAG, +"buffer\0", 0x00010000L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_COMMAND, +"status\0", 0x00000814L, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_CONSTANT, +"position\0", 0x00000002L, MCI_INTEGER, +"length\0", 0x00000001L, MCI_INTEGER, +"number of tracks\0", 0x00000003L, MCI_INTEGER, +"media present\0", 0x00000005L, MCI_INTEGER, +"mode\0", 0x00000004L, MCI_INTEGER, +"format tag\0", 0x00004001L, MCI_INTEGER, +"channels\0", 0x00004002L, MCI_INTEGER, +"samplespersec\0", 0x00004003L, MCI_INTEGER, +"bytespersec\0", 0x00004004L, MCI_INTEGER, +"alignment\0", 0x00004005L, MCI_INTEGER, +"bitspersample\0", 0x00004006L, MCI_INTEGER, +"input\0", 0x00400000L, MCI_INTEGER, +"output\0", 0x00800000L, MCI_INTEGER, +"level\0", 0x00004007L, MCI_INTEGER, +"ready\0", 0x00000007L, MCI_INTEGER, +"time format\0", 0x00000006L, MCI_INTEGER, +"current track\0", 0x00000008L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"track\0", 0x00000010L, MCI_INTEGER, +"start\0", 0x00000200L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"set\0", 0x0000080dL, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"any input\0", 0x04000000L, MCI_FLAG, +"any output\0", 0x08000000L, MCI_FLAG, +"time format\0", 0x00000400L, MCI_CONSTANT, +"milliseconds\0", 0x00000000L, MCI_INTEGER, +"ms\0", 0x00000000L, MCI_INTEGER, +"bytes\0", 0x00000008L, MCI_INTEGER, +"samples\0", 0x00000009L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"audio\0", 0x00000800L, MCI_CONSTANT, +"all\0", 0x00000000L, MCI_INTEGER, +"left\0", 0x00000001L, MCI_INTEGER, +"right\0", 0x00000002L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"video\0", 0x00001000L, MCI_FLAG, +"on\0", 0x00002000L, MCI_FLAG, +"off\0", 0x00004000L, MCI_FLAG, +"door open\0", 0x00000100L, MCI_FLAG, +"door closed\0", 0x00000200L, MCI_FLAG, +"input\0", 0x00400000L, MCI_INTEGER, +"output\0", 0x00800000L, MCI_INTEGER, +"format tag\0", 0x00010000L, MCI_CONSTANT, +"pcm\0", 0x00000001L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"channels\0", 0x00020000L, MCI_INTEGER, +"samplespersec\0", 0x00040000L, MCI_INTEGER, +"bytespersec\0", 0x00080000L, MCI_INTEGER, +"alignment\0", 0x00100000L, MCI_INTEGER, +"bitspersample\0", 0x00200000L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_COMMAND, +"capability\0", 0x0000080bL, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_CONSTANT, +"can record\0", 0x00000001L, MCI_INTEGER, +"has audio\0", 0x00000002L, MCI_INTEGER, +"has video\0", 0x00000003L, MCI_INTEGER, +"device type\0", 0x00000004L, MCI_INTEGER, +"uses files\0", 0x00000005L, MCI_INTEGER, +"compound device\0", 0x00000006L, MCI_INTEGER, +"can eject\0", 0x00000007L, MCI_INTEGER, +"can play\0", 0x00000008L, MCI_INTEGER, +"can save\0", 0x00000009L, MCI_INTEGER, +"inputs\0", 0x00004001L, MCI_INTEGER, +"outputs\0", 0x00004002L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"\0", 0x00000000L, MCI_END_COMMAND, +"info\0", 0x0000080aL, MCI_COMMAND_HEAD, +"\0", 0x00000001L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"product\0", 0x00000100L, MCI_FLAG, +"input\0", 0x00400000L, MCI_FLAG, +"output\0", 0x00800000L, MCI_FLAG, +"file\0", 0x00000200L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"cue\0", 0x00000830L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"input\0", 0x00400000L, MCI_FLAG, +"output\0", 0x00800000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"delete\0", 0x00000856L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"from\0", 0x00000004L, MCI_INTEGER, +"to\0", 0x00000008L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_COMMAND, +"\0", 0x00000000L, MCI_END_COMMAND_LIST +END + +CDAUDIO RCDATA +BEGIN +"status\0", 0x00000814L, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_CONSTANT, +"position\0", 0x00000002L, MCI_INTEGER, +"length\0", 0x00000001L, MCI_INTEGER, +"number of tracks\0", 0x00000003L, MCI_INTEGER, +"ready\0", 0x00000007L, MCI_INTEGER, +"mode\0", 0x00000004L, MCI_INTEGER, +"media present\0", 0x00000005L, MCI_INTEGER, +"time format\0", 0x00000006L, MCI_INTEGER, +"current track\0", 0x00000008L, MCI_INTEGER, +"type\0", 0x00004001L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"track\0", 0x00000010L, MCI_INTEGER, +"start\0", 0x00000200L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"set\0", 0x0000080dL, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"time format\0", 0x00000400L, MCI_CONSTANT, +"msf\0", 0x00000002L, MCI_INTEGER, +"tmsf\0", 0x0000000aL, MCI_INTEGER, +"milliseconds\0", 0x00000000L, MCI_INTEGER, +"ms\0", 0x00000000L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"audio\0", 0x00000800L, MCI_CONSTANT, +"all\0", 0x00000000L, MCI_INTEGER, +"left\0", 0x00000001L, MCI_INTEGER, +"right\0", 0x00000002L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"video\0", 0x00001000L, MCI_FLAG, +"on\0", 0x00002000L, MCI_FLAG, +"off\0", 0x00004000L, MCI_FLAG, +"door open\0", 0x00000100L, MCI_FLAG, +"door closed\0", 0x00000200L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"info\0", 0x0000080aL, MCI_COMMAND_HEAD, +"\0", 0x00000001L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"product\0", 0x00000100L, MCI_FLAG, +"upc\0", 0x00000400L, MCI_FLAG, +"identity\0", 0x00000800L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"\0", 0x00000000L, MCI_END_COMMAND_LIST +END + +SEQUENCER RCDATA +BEGIN +"status\0", 0x00000814L, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_CONSTANT, +"position\0", 0x00000002L, MCI_INTEGER, +"mode\0", 0x00000004L, MCI_INTEGER, +"length\0", 0x00000001L, MCI_INTEGER, +"number of tracks\0", 0x00000003L, MCI_INTEGER, +"media present\0", 0x00000005L, MCI_INTEGER, +"ready\0", 0x00000007L, MCI_INTEGER, +"tempo\0", 0x00004002L, MCI_INTEGER, +"port\0", 0x00004003L, MCI_INTEGER, +"slave\0", 0x00004007L, MCI_INTEGER, +"master\0", 0x00004008L, MCI_INTEGER, +"offset\0", 0x00004009L, MCI_INTEGER, +"division type\0", 0x0000400aL, MCI_INTEGER, +"time format\0", 0x00000006L, MCI_INTEGER, +"current track\0", 0x00000008L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"track\0", 0x00000010L, MCI_INTEGER, +"start\0", 0x00000200L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"set\0", 0x0000080dL, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"time format\0", 0x00000400L, MCI_CONSTANT, +"milliseconds\0", 0x00000000L, MCI_INTEGER, +"ms\0", 0x00000000L, MCI_INTEGER, +"smpte 30 drop\0", 0x00000007L, MCI_INTEGER, +"smpte 30\0", 0x00000006L, MCI_INTEGER, +"smpte 25\0", 0x00000005L, MCI_INTEGER, +"smpte 24\0", 0x00000004L, MCI_INTEGER, +"song pointer\0", 0x00004001L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"audio\0", 0x00000800L, MCI_CONSTANT, +"all\0", 0x00000000L, MCI_INTEGER, +"left\0", 0x00000001L, MCI_INTEGER, +"right\0", 0x00000002L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"video\0", 0x00001000L, MCI_FLAG, +"on\0", 0x00002000L, MCI_FLAG, +"off\0", 0x00004000L, MCI_FLAG, +"tempo\0", 0x00010000L, MCI_INTEGER, +"port\0", 0x00020000L, MCI_CONSTANT, +"none\0", 0x0000fffdL, MCI_INTEGER, +"mapper\0", 0x0000ffffL, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"slave\0", 0x00040000L, MCI_CONSTANT, +"smpte\0", 0x00004004L, MCI_INTEGER, +"midi\0", 0x00004003L, MCI_INTEGER, +"none\0", 0x0000fffdL, MCI_INTEGER, +"file\0", 0x00004002L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"master\0", 0x00080000L, MCI_CONSTANT, +"smpte\0", 0x00004004L, MCI_INTEGER, +"midi\0", 0x00004003L, MCI_INTEGER, +"none\0", 0x0000fffdL, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"offset\0", 0x01000000L, MCI_INTEGER, +"door open\0", 0x00000100L, MCI_FLAG, +"door closed\0", 0x00000200L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"info\0", 0x0000080aL, MCI_COMMAND_HEAD, +"\0", 0x00000001L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"product\0", 0x00000100L, MCI_FLAG, +"file\0", 0x00000200L, MCI_FLAG, +"name\0", 0x00001000L, MCI_FLAG, +"copyright\0", 0x00002000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"\0", 0x00000000L, MCI_END_COMMAND_LIST +END + +ANIMATION RCDATA +BEGIN +"open\0", 0x00000803L, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"type\0", 0x00002000L, MCI_STRING, +"element\0", 0x00000200L, MCI_STRING, +"alias\0", 0x00000400L, MCI_STRING, +"shareable\0", 0x00000100L, MCI_FLAG, +"style\0", 0x00010000L, MCI_CONSTANT, +"overlapped\0", 0x00cf0000L, MCI_INTEGER, +"popup\0", 0x80880000L, MCI_INTEGER, +"child\0", 0x40000000L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"parent\0", 0x00020000L, MCI_INTEGER, +"nostatic\0", 0x00040000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"play\0", 0x00000806L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"from\0", 0x00000004L, MCI_INTEGER, +"to\0", 0x00000008L, MCI_INTEGER, +"fast\0", 0x00040000L, MCI_FLAG, +"slow\0", 0x00080000L, MCI_FLAG, +"scan\0", 0x00100000L, MCI_FLAG, +"reverse\0", 0x00020000L, MCI_FLAG, +"speed\0", 0x00010000L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_COMMAND, +"step\0", 0x0000080eL, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"reverse\0", 0x00010000L, MCI_FLAG, +"by\0", 0x00020000L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_COMMAND, +"set\0", 0x0000080dL, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"time format\0", 0x00000400L, MCI_CONSTANT, +"milliseconds\0", 0x00000000L, MCI_INTEGER, +"ms\0", 0x00000000L, MCI_INTEGER, +"frames\0", 0x00000003L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"audio\0", 0x00000800L, MCI_CONSTANT, +"all\0", 0x00000000L, MCI_INTEGER, +"left\0", 0x00000001L, MCI_INTEGER, +"right\0", 0x00000002L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"video\0", 0x00001000L, MCI_FLAG, +"on\0", 0x00002000L, MCI_FLAG, +"off\0", 0x00004000L, MCI_FLAG, +"door open\0", 0x00000100L, MCI_FLAG, +"door closed\0", 0x00000200L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"status\0", 0x00000814L, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_CONSTANT, +"position\0", 0x00000002L, MCI_INTEGER, +"length\0", 0x00000001L, MCI_INTEGER, +"number of tracks\0", 0x00000003L, MCI_INTEGER, +"mode\0", 0x00000004L, MCI_INTEGER, +"ready\0", 0x00000007L, MCI_INTEGER, +"speed\0", 0x00004001L, MCI_INTEGER, +"forward\0", 0x00004002L, MCI_INTEGER, +"window handle\0", 0x00004003L, MCI_INTEGER, +"palette handle\0", 0x00004004L, MCI_INTEGER, +"media present\0", 0x00000005L, MCI_INTEGER, +"time format\0", 0x00000006L, MCI_INTEGER, +"current track\0", 0x00000008L, MCI_INTEGER, +"stretch\0", 0x00004005L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"track\0", 0x00000010L, MCI_INTEGER, +"start\0", 0x00000200L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"info\0", 0x0000080aL, MCI_COMMAND_HEAD, +"\0", 0x00000001L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"product\0", 0x00000100L, MCI_FLAG, +"file\0", 0x00000200L, MCI_FLAG, +"window text\0", 0x00010000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"capability\0", 0x0000080bL, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_CONSTANT, +"can record\0", 0x00000001L, MCI_INTEGER, +"has audio\0", 0x00000002L, MCI_INTEGER, +"has video\0", 0x00000003L, MCI_INTEGER, +"device type\0", 0x00000004L, MCI_INTEGER, +"uses files\0", 0x00000005L, MCI_INTEGER, +"compound device\0", 0x00000006L, MCI_INTEGER, +"can eject\0", 0x00000007L, MCI_INTEGER, +"can play\0", 0x00000008L, MCI_INTEGER, +"can save\0", 0x00000009L, MCI_INTEGER, +"can reverse\0", 0x00004001L, MCI_INTEGER, +"fast play rate\0", 0x00004002L, MCI_INTEGER, +"slow play rate\0", 0x00004003L, MCI_INTEGER, +"normal play rate\0", 0x00004004L, MCI_INTEGER, +"uses palettes\0", 0x00004006L, MCI_INTEGER, +"can stretch\0", 0x00004007L, MCI_INTEGER, +"windows\0", 0x00004008L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"\0", 0x00000000L, MCI_END_COMMAND, +"realize\0", 0x00000840L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"normal\0", 0x00010000L, MCI_FLAG, +"background\0", 0x00020000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"window\0", 0x00000841L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"handle\0", 0x00010000L, MCI_CONSTANT, +"default\0", 0x00000000L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"state\0", 0x00040000L, MCI_CONSTANT, +"hide\0", 0x00000000L, MCI_INTEGER, +"minimize\0", 0x00000006L, MCI_INTEGER, +"show\0", 0x00000005L, MCI_INTEGER, +"maximized\0", 0x00000003L, MCI_INTEGER, +"minimized\0", 0x00000002L, MCI_INTEGER, +"iconic\0", 0x00000007L, MCI_INTEGER, +"no action\0", 0x00000008L, MCI_INTEGER, +"no activate\0", 0x00000004L, MCI_INTEGER, +"normal\0", 0x00000001L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"text\0", 0x00080000L, MCI_STRING, +"stretch\0", 0x00100000L, MCI_FLAG, +"fixed\0", 0x00200000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"put\0", 0x00000842L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"at\0", 0x00010000L, MCI_RECT, +"source\0", 0x00020000L, MCI_FLAG, +"destination\0", 0x00040000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"where\0", 0x00000843L, MCI_COMMAND_HEAD, +"\0", 0x00000007L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"source\0", 0x00020000L, MCI_FLAG, +"destination\0", 0x00040000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"update\0", 0x00000854L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"at\0", 0x00010000L, MCI_RECT, +"hdc\0", 0x00020000L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_COMMAND, +"\0", 0x00000000L, MCI_END_COMMAND_LIST +END + +OVERLAY RCDATA +BEGIN +"open\0", 0x00000803L, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"type\0", 0x00002000L, MCI_STRING, +"element\0", 0x00000200L, MCI_STRING, +"alias\0", 0x00000400L, MCI_STRING, +"shareable\0", 0x00000100L, MCI_FLAG, +"style\0", 0x00010000L, MCI_CONSTANT, +"overlapped\0", 0x00cf0000L, MCI_INTEGER, +"popup\0", 0x80880000L, MCI_INTEGER, +"child\0", 0x40000000L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"parent\0", 0x00020000L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_COMMAND, +"status\0", 0x00000814L, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_CONSTANT, +"position\0", 0x00000002L, MCI_INTEGER, +"length\0", 0x00000001L, MCI_INTEGER, +"number of tracks\0", 0x00000003L, MCI_INTEGER, +"mode\0", 0x00000004L, MCI_INTEGER, +"ready\0", 0x00000007L, MCI_INTEGER, +"window handle\0", 0x00004001L, MCI_INTEGER, +"media present\0", 0x00000005L, MCI_INTEGER, +"stretch\0", 0x00004002L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"track\0", 0x00000010L, MCI_INTEGER, +"start\0", 0x00000200L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"info\0", 0x0000080aL, MCI_COMMAND_HEAD, +"\0", 0x00000001L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"product\0", 0x00000100L, MCI_FLAG, +"file\0", 0x00000200L, MCI_FLAG, +"window text\0", 0x00010000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"capability\0", 0x0000080bL, MCI_COMMAND_HEAD, +"\0", 0x00000002L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_CONSTANT, +"can record\0", 0x00000001L, MCI_INTEGER, +"has audio\0", 0x00000002L, MCI_INTEGER, +"has video\0", 0x00000003L, MCI_INTEGER, +"device type\0", 0x00000004L, MCI_INTEGER, +"uses files\0", 0x00000005L, MCI_INTEGER, +"compound device\0", 0x00000006L, MCI_INTEGER, +"can eject\0", 0x00000007L, MCI_INTEGER, +"can play\0", 0x00000008L, MCI_INTEGER, +"can save\0", 0x00000009L, MCI_INTEGER, +"can stretch\0", 0x00004001L, MCI_INTEGER, +"can freeze\0", 0x00004002L, MCI_INTEGER, +"windows\0", 0x00004003L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"\0", 0x00000000L, MCI_END_COMMAND, +"window\0", 0x00000841L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"handle\0", 0x00010000L, MCI_CONSTANT, +"default\0", 0x00000000L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"state\0", 0x00040000L, MCI_CONSTANT, +"hide\0", 0x00000000L, MCI_INTEGER, +"minimize\0", 0x00000006L, MCI_INTEGER, +"show\0", 0x00000005L, MCI_INTEGER, +"maximized\0", 0x00000003L, MCI_INTEGER, +"minimized\0", 0x00000002L, MCI_INTEGER, +"iconic\0", 0x00000007L, MCI_INTEGER, +"no action\0", 0x00000008L, MCI_INTEGER, +"no activate\0", 0x00000004L, MCI_INTEGER, +"normal\0", 0x00000001L, MCI_INTEGER, +"\0", 0x00000000L, MCI_END_CONSTANT, +"text\0", 0x00080000L, MCI_STRING, +"stretch\0", 0x00100000L, MCI_FLAG, +"fixed\0", 0x00200000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"put\0", 0x00000842L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"at\0", 0x00010000L, MCI_RECT, +"source\0", 0x00020000L, MCI_FLAG, +"destination\0", 0x00040000L, MCI_FLAG, +"frame\0", 0x00080000L, MCI_FLAG, +"video\0", 0x00100000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"where\0", 0x00000843L, MCI_COMMAND_HEAD, +"\0", 0x00000007L, MCI_RETURN, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"source\0", 0x00020000L, MCI_FLAG, +"destination\0", 0x00040000L, MCI_FLAG, +"frame\0", 0x00080000L, MCI_FLAG, +"video\0", 0x00100000L, MCI_FLAG, +"\0", 0x00000000L, MCI_END_COMMAND, +"save\0", 0x00000813L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_STRING, +"at\0", 0x00010000L, MCI_RECT, +"\0", 0x00000000L, MCI_END_COMMAND, +"load\0", 0x00000850L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"\0", 0x00000100L, MCI_STRING, +"at\0", 0x00010000L, MCI_RECT, +"\0", 0x00000000L, MCI_END_COMMAND, +"freeze\0", 0x00000844L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"at\0", 0x00010000L, MCI_RECT, +"\0", 0x00000000L, MCI_END_COMMAND, +"unfreeze\0", 0x00000845L, MCI_COMMAND_HEAD, +"notify\0", 0x00000001L, MCI_FLAG, +"wait\0", 0x00000002L, MCI_FLAG, +"at\0", 0x00010000L, MCI_RECT, +"\0", 0x00000000L, MCI_END_COMMAND, +"\0", 0x00000000L, MCI_END_COMMAND_LIST +END + +STRINGTABLE +BEGIN + +MCI_DEVTYPE_VCR, "vcr" +MCI_DEVTYPE_VIDEODISC, "videodisc" +MCI_DEVTYPE_OVERLAY, "overlay" +MCI_DEVTYPE_CD_AUDIO, "cdaudio" +MCI_DEVTYPE_DAT, "dat" +MCI_DEVTYPE_SCANNER, "scanner" +MCI_DEVTYPE_ANIMATION, "animation" +MCI_DEVTYPE_DIGITAL_VIDEO, "digitalvideo" +MCI_DEVTYPE_OTHER, "other" +MCI_DEVTYPE_WAVEFORM_AUDIO, "waveaudio" +MCI_DEVTYPE_SEQUENCER, "sequencer" + +MCI_MODE_NOT_READY, "not ready" +MCI_MODE_STOP, "stopped" +MCI_MODE_PLAY, "playing" +MCI_MODE_RECORD, "recording" +MCI_MODE_SEEK, "seeking" +MCI_MODE_PAUSE, "paused" +MCI_MODE_OPEN, "open" +MCI_FALSE, "false" +MCI_TRUE, "true" +MCI_FORMAT_MILLISECONDS_S, "milliseconds" +MCI_FORMAT_HMS_S, "hms" +MCI_FORMAT_MSF_S, "msf" +MCI_FORMAT_FRAMES_S, "frames" +MCI_FORMAT_SMPTE_24_S, "smpte 24" +MCI_FORMAT_SMPTE_25_S, "smpte 25" +MCI_FORMAT_SMPTE_30_S, "smpte 30" +MCI_FORMAT_SMPTE_30DROP_S, "smpte 30 drop" +MCI_FORMAT_BYTES_S, "bytes" +MCI_FORMAT_SAMPLES_S, "samples" +MCI_FORMAT_TMSF_S, "tmsf" + +MCI_VD_MODE_PARK, "parked" +MCI_VD_MEDIA_CLV, "CLV" +MCI_VD_MEDIA_CAV, "CAV" +MCI_VD_MEDIA_OTHER "other" + +MCI_VD_FORMAT_TRACK_S, "track" + +MCI_SEQ_DIV_PPQN, "PPQN" +MCI_SEQ_DIV_SMPTE_24 "SMPTE 24 Frame" +MCI_SEQ_DIV_SMPTE_25 "SMPTE 25 Frame" +MCI_SEQ_DIV_SMPTE_30DROP "SMPTE 30 Drop Frame" +MCI_SEQ_DIV_SMPTE_30 "SMPTE 30 Frame" + +MCI_SEQ_FILE_S, "file" +MCI_SEQ_MIDI_S, "midi" +MCI_SEQ_SMPTE_S, "smpte" +MCI_SEQ_FORMAT_SONGPTR_S, "song pointer" +MCI_SEQ_NONE_S, "none" +MCI_SEQ_MAPPER_S, "mapper" +WAVE_FORMAT_PCM_S, "pcm" +WAVE_MAPPER_S, "mapper" +END