1369 lines
41 KiB
C
1369 lines
41 KiB
C
/* -*- tab-width: 8; c-basic-offset: 4 -*- */
|
|
|
|
/*
|
|
* MCI internal functions
|
|
*
|
|
* Copyright 1998/1999 Eric Pouech
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "winbase.h"
|
|
#include "winuser.h"
|
|
#include "heap.h"
|
|
#include "driver.h"
|
|
#include "mmsystem.h"
|
|
#include "multimedia.h"
|
|
#include "selectors.h"
|
|
#include "debug.h"
|
|
#include "digitalv.h"
|
|
#include "wine/winbase16.h"
|
|
|
|
struct WINE_MCIDRIVER mciDrv[MAXMCIDRIVERS];
|
|
|
|
int mciInstalledCount;
|
|
int mciInstalledListLen;
|
|
LPSTR lpmciInstallNames = NULL;
|
|
|
|
/* The wDevID's returned by wine were originally in the range
|
|
* 0 - (MAXMCIDRIVERS - 1) and used directly as array indices.
|
|
* Unfortunately, ms-windows uses wDevID of zero to indicate
|
|
* errors. Now, multimedia drivers must pass the wDevID through
|
|
* MCI_DevIDToIndex to get an index in that range. An
|
|
* arbitrary value, MCI_MAGIC is added to the wDevID seen
|
|
* by the windows programs.
|
|
*/
|
|
|
|
#define MCI_MAGIC 0x0F00
|
|
|
|
MCI_WineDesc MCI_InternalDescriptors[] = {
|
|
{MCI_DEVTYPE_CD_AUDIO, "CDAUDIO", MCICDAUDIO_DriverProc},
|
|
{MCI_DEVTYPE_WAVEFORM_AUDIO, "WAVEAUDIO", MCIWAVE_DriverProc},
|
|
{MCI_DEVTYPE_SEQUENCER, "SEQUENCER", MCIMIDI_DriverProc},
|
|
{MCI_DEVTYPE_ANIMATION, "ANIMATION1", MCIANIM_DriverProc},
|
|
{MCI_DEVTYPE_DIGITAL_VIDEO, "AVIVIDEO", MCIAVI_DriverProc},
|
|
|
|
{0xFFFF, NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
/**************************************************************************
|
|
* MCI_GetDevTypeString [internal]
|
|
*/
|
|
static LPCSTR MCI_GetDevTypeString(WORD uDevType)
|
|
{
|
|
LPCSTR str = "??? MCI ???";
|
|
int i;
|
|
|
|
for (i = 0; MCI_InternalDescriptors[i].uDevType != 0xFFFF; i++) {
|
|
if (MCI_InternalDescriptors[i].uDevType != 0 && MCI_InternalDescriptors[i].uDevType == uDevType) {
|
|
str = MCI_InternalDescriptors[i].lpstrName;
|
|
break;
|
|
}
|
|
}
|
|
/* TRACE(mci, "devType=%u => %s\n", uDevType, str);*/
|
|
return str;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_GetProc [internal]
|
|
*/
|
|
static MCIPROC MCI_GetProc(UINT16 uDevType)
|
|
{
|
|
MCIPROC proc = 0;
|
|
int i;
|
|
|
|
for (i = 0; MCI_InternalDescriptors[i].uDevType != 0xFFFF; i++) {
|
|
if (MCI_InternalDescriptors[i].uDevType != 0 &&
|
|
MCI_InternalDescriptors[i].uDevType == uDevType) {
|
|
proc = MCI_InternalDescriptors[i].lpfnProc;
|
|
break;
|
|
}
|
|
}
|
|
return proc;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_GetDevType [internal]
|
|
*/
|
|
WORD MCI_GetDevType(LPCSTR str)
|
|
{
|
|
WORD uDevType = 0;
|
|
int i;
|
|
|
|
for (i = 0; MCI_InternalDescriptors[i].uDevType != 0xFFFF; i++) {
|
|
if (MCI_InternalDescriptors[i].uDevType != 0 &&
|
|
strcmp(str, MCI_InternalDescriptors[i].lpstrName) == 0) {
|
|
uDevType = MCI_InternalDescriptors[i].uDevType;
|
|
break;
|
|
}
|
|
}
|
|
return uDevType;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_DevIDToIndex [internal]
|
|
*/
|
|
int MCI_DevIDToIndex(UINT16 wDevID)
|
|
{
|
|
return wDevID - MCI_MAGIC;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_FirstDevId [internal]
|
|
*/
|
|
UINT16 MCI_FirstDevID(void)
|
|
{
|
|
return MCI_MAGIC;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_NextDevId [internal]
|
|
*/
|
|
UINT16 MCI_NextDevID(UINT16 wDevID)
|
|
{
|
|
return wDevID + 1;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_DevIDValid [internal]
|
|
*/
|
|
BOOL MCI_DevIDValid(UINT16 wDevID)
|
|
{
|
|
return wDevID >= MCI_MAGIC && wDevID < (MCI_MAGIC + MAXMCIDRIVERS);
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_CommandToString [internal]
|
|
*/
|
|
const char* MCI_CommandToString(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);
|
|
default:
|
|
sprintf(buffer, "MCI_<<%04X>>", wMsg);
|
|
return buffer;
|
|
}
|
|
#undef CASE
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_MapMsg16To32A [internal]
|
|
*/
|
|
int MCI_MapMsg16To32A(WORD uDevType, WORD wMsg, DWORD* lParam)
|
|
{
|
|
if (*lParam == 0)
|
|
return 0;
|
|
/* 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)PTR_SEG_TO_LIN(*lParam);
|
|
return 0;
|
|
case MCI_WINDOW:
|
|
/* in fact, I would also need the dwFlags... to see
|
|
* which members of lParam are effectively used
|
|
*/
|
|
*lParam = (DWORD)PTR_SEG_TO_LIN(*lParam);
|
|
FIXME(mci, "Current mapping may be wrong\n");
|
|
break;
|
|
case MCI_BREAK:
|
|
{
|
|
LPMCI_BREAK_PARMS mbp32 = HeapAlloc(SystemHeap, 0, sizeof(MCI_BREAK_PARMS));
|
|
LPMCI_BREAK_PARMS16 mbp16 = PTR_SEG_TO_LIN(*lParam);
|
|
|
|
if (mbp32) {
|
|
mbp32->dwCallback = mbp16->dwCallback;
|
|
mbp32->nVirtKey = mbp16->nVirtKey;
|
|
mbp32->hwndBreak = mbp16->hwndBreak;
|
|
} else {
|
|
return -2;
|
|
}
|
|
*lParam = (DWORD)mbp32;
|
|
}
|
|
return 1;
|
|
case MCI_ESCAPE:
|
|
{
|
|
LPMCI_VD_ESCAPE_PARMSA mvep32a = HeapAlloc(SystemHeap, 0, sizeof(MCI_VD_ESCAPE_PARMSA));
|
|
LPMCI_VD_ESCAPE_PARMS16 mvep16 = PTR_SEG_TO_LIN(*lParam);
|
|
|
|
if (mvep32a) {
|
|
mvep32a->dwCallback = mvep16->dwCallback;
|
|
mvep32a->lpstrCommand = PTR_SEG_TO_LIN(mvep16->lpstrCommand);
|
|
} else {
|
|
return -2;
|
|
}
|
|
*lParam = (DWORD)mvep32a;
|
|
}
|
|
return 1;
|
|
case MCI_INFO:
|
|
{
|
|
LPMCI_INFO_PARMSA mip32a = HeapAlloc(SystemHeap, 0, sizeof(MCI_INFO_PARMSA));
|
|
LPMCI_INFO_PARMS16 mip16 = PTR_SEG_TO_LIN(*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 = PTR_SEG_TO_LIN(mip16->lpstrReturn);
|
|
mip32a->dwRetSize = mip16->dwRetSize;
|
|
} else {
|
|
return -2;
|
|
}
|
|
*lParam = (DWORD)mip32a;
|
|
}
|
|
return 1;
|
|
case MCI_OPEN:
|
|
case MCI_OPEN_DRIVER:
|
|
{
|
|
LPMCI_OPEN_PARMSA mop32a = HeapAlloc(SystemHeap, 0, sizeof(LPMCI_OPEN_PARMS16) + sizeof(MCI_OPEN_PARMSA) + 2 * sizeof(DWORD));
|
|
LPMCI_OPEN_PARMS16 mop16 = PTR_SEG_TO_LIN(*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 = PTR_SEG_TO_LIN(mop16->lpstrDeviceType);
|
|
mop32a->lpstrElementName = PTR_SEG_TO_LIN(mop16->lpstrElementName);
|
|
mop32a->lpstrAlias = PTR_SEG_TO_LIN(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 -2;
|
|
}
|
|
*lParam = (DWORD)mop32a;
|
|
}
|
|
return 1;
|
|
case MCI_SYSINFO:
|
|
{
|
|
LPMCI_SYSINFO_PARMSA msip32a = HeapAlloc(SystemHeap, 0, sizeof(MCI_SYSINFO_PARMSA));
|
|
LPMCI_SYSINFO_PARMS16 msip16 = PTR_SEG_TO_LIN(*lParam);
|
|
|
|
if (msip32a) {
|
|
msip32a->dwCallback = msip16->dwCallback;
|
|
msip32a->lpstrReturn = PTR_SEG_TO_LIN(msip16->lpstrReturn);
|
|
msip32a->dwRetSize = msip16->dwRetSize;
|
|
msip32a->dwNumber = msip16->dwNumber;
|
|
msip32a->wDeviceType = msip16->wDeviceType;
|
|
} else {
|
|
return -2;
|
|
}
|
|
*lParam = (DWORD)msip32a;
|
|
}
|
|
return 1;
|
|
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(mci, "This is a hack\n");
|
|
return 0;
|
|
|
|
default:
|
|
WARN(mci, "Don't know how to map msg=%s\n", MCI_CommandToString(wMsg));
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_UnMapMsg16To32A [internal]
|
|
*/
|
|
int 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 0;
|
|
|
|
case MCI_WINDOW:
|
|
/* FIXME ?? see Map function */
|
|
return 0;
|
|
|
|
case MCI_BREAK:
|
|
case MCI_ESCAPE:
|
|
case MCI_INFO:
|
|
case MCI_SYSINFO:
|
|
HeapFree(SystemHeap, 0, (LPVOID)lParam);
|
|
return 0;
|
|
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(SystemHeap, 0, (LPVOID)(lParam - sizeof(LPMCI_OPEN_PARMS16))))
|
|
FIXME(mci, "bad free line=%d\n", __LINE__);
|
|
}
|
|
return 0;
|
|
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(mci, "This is a hack\n");
|
|
return 0;
|
|
default:
|
|
FIXME(mci, "Map/Unmap internal error on msg=%s\n", MCI_CommandToString(wMsg));
|
|
}
|
|
return -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.
|
|
* if keep is TRUE, keeps track of in 32 bit ptr in allocated 16 bit area.
|
|
* 1 : ok, some memory allocated
|
|
* -2 : ko, memory problem
|
|
*/
|
|
static int MCI_MsgMapper32To16_Create(void** ptr, int size, BOOLEAN keep)
|
|
{
|
|
void* lp = SEGPTR_ALLOC(sizeof(void**) + size);
|
|
|
|
if (!lp) {
|
|
return -2;
|
|
}
|
|
if (keep) {
|
|
*(void**)lp = *ptr;
|
|
memcpy((char*)lp + sizeof(void**), *ptr, size);
|
|
*ptr = (char*)SEGPTR_GET(lp) + sizeof(void**);
|
|
} else {
|
|
memcpy((char*)lp, *ptr, size);
|
|
*ptr = (void*)SEGPTR_GET(lp);
|
|
}
|
|
return 1;
|
|
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_MsgMapper32To16_Destroy [internal]
|
|
*
|
|
* Helper for MCI_UnMapMsg32ATo16.
|
|
*/
|
|
static int MCI_MsgMapper32To16_Destroy(void* ptr, int size, BOOLEAN kept)
|
|
{
|
|
if (ptr) {
|
|
void* msg16 = PTR_SEG_TO_LIN(ptr);
|
|
void* alloc;
|
|
|
|
if (kept) {
|
|
alloc = (char*)msg16 - sizeof(void**);
|
|
memcpy(*(void**)alloc, msg16, size);
|
|
} else {
|
|
alloc = msg16;
|
|
}
|
|
|
|
if (!SEGPTR_FREE(alloc)) {
|
|
FIXME(mci, "bad free\n");
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_MapMsg32ATo16 [internal]
|
|
*
|
|
* Map a 32-A bit MCI message to a 16 bit MCI message.
|
|
* 1 : ok, some memory allocated, need to call MCI_UnMapMsg32ATo16
|
|
* 0 : ok, no memory allocated
|
|
* -1 : ko, unknown message
|
|
* -2 : ko, memory problem
|
|
*/
|
|
int MCI_MapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD* lParam)
|
|
{
|
|
int size;
|
|
BOOLEAN keep = FALSE;
|
|
|
|
if (*lParam == 0)
|
|
return 0;
|
|
/* 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: */
|
|
/* case MCI_CAPTURE */
|
|
case MCI_CLOSE:
|
|
case MCI_CLOSE_DRIVER:
|
|
size = sizeof(MCI_GENERIC_PARMS);
|
|
break;
|
|
/* case MCI_CONFIGURE:*/
|
|
/* 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(mci, "NIY vcr\n"); return -2;
|
|
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_PARMS); FIXME(mci, "NIY rect\n"); return -2;
|
|
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); FIXME(mci, "NIY rect\n"); return -2;
|
|
case MCI_DEVTYPE_OVERLAY: /*size = sizeof(MCI_OVLY_FREEZE_PARMS); FIXME(mci, "NIY rect\n"); return -2;*/
|
|
FIXME(mci, "NIY ovly\n"); return -2;
|
|
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);
|
|
char* ptr;
|
|
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;
|
|
}
|
|
ptr = SEGPTR_ALLOC(sizeof(LPMCI_INFO_PARMSA) + size);
|
|
|
|
if (ptr) {
|
|
*(LPMCI_INFO_PARMSA*)ptr = mip32a;
|
|
mip16 = (LPMCI_INFO_PARMS16)(ptr + sizeof(LPMCI_INFO_PARMSA));
|
|
mip16->dwCallback = mip32a->dwCallback;
|
|
mip16->lpstrReturn = (LPSTR)SEGPTR_GET(SEGPTR_ALLOC(mip32a->dwRetSize));
|
|
mip16->dwRetSize = mip32a->dwRetSize;
|
|
if (uDevType == MCI_DEVTYPE_DIGITAL_VIDEO) {
|
|
((LPMCI_DGV_INFO_PARMS16)mip16)->dwItem = ((LPMCI_DGV_INFO_PARMSA)mip32a)->dwItem;
|
|
}
|
|
} else {
|
|
return -2;
|
|
}
|
|
*lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_INFO_PARMSA);
|
|
}
|
|
return 1;
|
|
/* case MCI_MARK: */
|
|
/* case MCI_MONITOR: */
|
|
case MCI_OPEN:
|
|
case MCI_OPEN_DRIVER:
|
|
{
|
|
LPMCI_OPEN_PARMSA mop32a = (LPMCI_OPEN_PARMSA)(*lParam);
|
|
char* ptr = SEGPTR_ALLOC(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 = mop32a->lpstrDeviceType;
|
|
} else {
|
|
/* string */
|
|
mop16->lpstrDeviceType = mop32a->lpstrDeviceType ? (LPSTR)SEGPTR_GET(SEGPTR_STRDUP(mop32a->lpstrDeviceType)) : 0;
|
|
}
|
|
} else {
|
|
/* nuthin' */
|
|
mop16->lpstrDeviceType = 0;
|
|
}
|
|
if (dwFlags & MCI_OPEN_ELEMENT) {
|
|
if (dwFlags & MCI_OPEN_ELEMENT_ID) {
|
|
mop16->lpstrElementName = mop32a->lpstrElementName;
|
|
} else {
|
|
mop16->lpstrElementName = mop32a->lpstrElementName ? (LPSTR)SEGPTR_GET(SEGPTR_STRDUP(mop32a->lpstrElementName)) : 0;
|
|
}
|
|
} else {
|
|
mop16->lpstrElementName = 0;
|
|
}
|
|
if (dwFlags & MCI_OPEN_ALIAS) {
|
|
mop16->lpstrAlias = mop32a->lpstrAlias ? (LPSTR)SEGPTR_GET(SEGPTR_STRDUP(mop32a->lpstrAlias)) : 0;
|
|
} 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 -2;
|
|
}
|
|
*lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_OPEN_PARMSA);
|
|
}
|
|
return 1;
|
|
/* case MCI_PASTE:*/
|
|
case MCI_PAUSE:
|
|
size = sizeof(MCI_GENERIC_PARMS);
|
|
break;
|
|
case MCI_PLAY:
|
|
switch (uDevType) {
|
|
case MCI_DEVTYPE_OVERLAY: /*size = sizeof(MCI_OVLY_PLAY_PARMS); break;*/FIXME(mci, "NIY ovly\n"); return -2;
|
|
default: size = sizeof(MCI_PLAY_PARMS); break;
|
|
}
|
|
break;
|
|
case MCI_PUT:
|
|
switch (uDevType) {
|
|
case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_PUT_PARMS); FIXME(mci, "NIY rect\n"); return -2;
|
|
case MCI_DEVTYPE_OVERLAY: /*size = sizeof(MCI_OVLY_PUT_PARMS); FIXME(mci, "NIY rect\n"); return -2;*/
|
|
FIXME(mci, "NIY ovly\n"); return -2;
|
|
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_PARMS); FIXME(mci, "NIY rect\n"); return -2;
|
|
case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_RECORD_PARMS); break;*/FIXME(mci, "NIY vcr\n"); return -2;
|
|
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(mci, "NIY vcr\n"); return -2;
|
|
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(mci, "NIY vcr\n"); return -2;
|
|
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_SETTIMECODE:*/
|
|
/* case MCI_SIGNAL:*/
|
|
case MCI_SPIN:
|
|
size = sizeof(MCI_SET_PARMS);
|
|
break;
|
|
case MCI_STATUS:
|
|
keep = TRUE;
|
|
switch (uDevType) {
|
|
case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STATUS_PARMS16); FIXME(mci, "NIY lpstrDevice\n");return -2;
|
|
case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STATUS_PARMS); break;*/FIXME(mci, "NIY vcr\n"); return -2;
|
|
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(mci, "NIY vcr\n"); return -2;
|
|
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);
|
|
char* ptr = SEGPTR_ALLOC(sizeof(LPMCI_SYSINFO_PARMSA) + sizeof(MCI_SYSINFO_PARMS16));
|
|
LPMCI_SYSINFO_PARMS16 msip16;
|
|
|
|
if (ptr) {
|
|
*(LPMCI_SYSINFO_PARMSA*)(ptr) = msip32a;
|
|
msip16 = (LPMCI_SYSINFO_PARMS16)(ptr + sizeof(LPMCI_SYSINFO_PARMSA));
|
|
|
|
msip16->dwCallback = msip32a->dwCallback;
|
|
msip16->lpstrReturn = (LPSTR)SEGPTR_GET(SEGPTR_ALLOC(msip32a->dwRetSize));
|
|
msip16->dwRetSize = msip32a->dwRetSize;
|
|
msip16->dwNumber = msip32a->dwNumber;
|
|
msip16->wDeviceType = msip32a->wDeviceType;
|
|
} else {
|
|
return -2;
|
|
}
|
|
*lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_SYSINFO_PARMSA);
|
|
}
|
|
return 1;
|
|
/* case MCI_UNDO: */
|
|
case MCI_UNFREEZE:
|
|
switch (uDevType) {
|
|
case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS); FIXME(mci, "NIY rect\n"); return -2;
|
|
case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS); FIXME(mci, "NIY rect\n"); return -2;
|
|
default: size = sizeof(MCI_GENERIC_PARMS); break;
|
|
}
|
|
break;
|
|
case MCI_UPDATE:
|
|
switch (uDevType) {
|
|
case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_UPDATE_PARMS); FIXME(mci, "NIY rect\n"); return -2;
|
|
default: size = sizeof(MCI_GENERIC_PARMS); break;
|
|
}
|
|
break;
|
|
case MCI_WHERE:
|
|
switch (uDevType) {
|
|
case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS); FIXME(mci, "NIY rect\n"); return -2;
|
|
case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS); FIXME(mci, "NIY rect\n"); return -2;
|
|
default: size = sizeof(MCI_GENERIC_PARMS); break;
|
|
}
|
|
break;
|
|
case MCI_WINDOW:
|
|
switch (uDevType) {
|
|
case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_WINDOW_PARMS16); FIXME(mci, "NIY lpstrText\n"); return -2;
|
|
case MCI_DEVTYPE_OVERLAY: /*size = sizeof(MCI_OVLY_WINDOW_PARMS); FIXME(mci, "NIY lpstrText\n"); return -2;*/
|
|
FIXME(mci, "NIY ovly\n"); return -2;
|
|
default: size = sizeof(MCI_GENERIC_PARMS); break;
|
|
}
|
|
break;
|
|
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(mci, "This is a hack\n");
|
|
return 0;
|
|
|
|
default:
|
|
WARN(mci, "Don't know how to map msg=%s\n", MCI_CommandToString(wMsg));
|
|
return -1;
|
|
}
|
|
return MCI_MsgMapper32To16_Create((void**)lParam, size, keep);
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_UnMapMsg32ATo16 [internal]
|
|
*/
|
|
int 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 */
|
|
|
|
switch (wMsg) {
|
|
/* case MCI_CAPTURE */
|
|
case MCI_CLOSE:
|
|
case MCI_CLOSE_DRIVER:
|
|
break;
|
|
/* case MCI_CONFIGURE:*/
|
|
/* 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)PTR_SEG_TO_LIN(lParam);
|
|
LPMCI_INFO_PARMSA mip32a = *(LPMCI_INFO_PARMSA*)((char*)mip16 - sizeof(LPMCI_INFO_PARMSA));
|
|
|
|
memcpy(mip32a->lpstrReturn, PTR_SEG_TO_LIN(mip16->lpstrReturn), mip32a->dwRetSize);
|
|
|
|
if (!SEGPTR_FREE(PTR_SEG_TO_LIN(mip16->lpstrReturn)))
|
|
FIXME(mci, "bad free line=%d\n", __LINE__);
|
|
if (!SEGPTR_FREE((char*)mip16 - sizeof(LPMCI_INFO_PARMSA)))
|
|
FIXME(mci, "bad free line=%d\n", __LINE__);
|
|
}
|
|
return 0;
|
|
/* case MCI_MARK: */
|
|
/* case MCI_MONITOR: */
|
|
case MCI_OPEN:
|
|
case MCI_OPEN_DRIVER:
|
|
if (lParam) {
|
|
LPMCI_OPEN_PARMS16 mop16 = (LPMCI_OPEN_PARMS16)PTR_SEG_TO_LIN(lParam);
|
|
LPMCI_OPEN_PARMSA mop32a = *(LPMCI_OPEN_PARMSA*)((char*)mop16 - sizeof(LPMCI_OPEN_PARMSA));
|
|
|
|
mop32a->wDeviceID = mop16->wDeviceID;
|
|
if ((dwFlags & MCI_OPEN_TYPE) && !
|
|
(dwFlags & MCI_OPEN_TYPE_ID) &&
|
|
!SEGPTR_FREE(PTR_SEG_TO_LIN(mop16->lpstrDeviceType)))
|
|
FIXME(mci, "bad free line=%d\n", __LINE__);
|
|
if ((dwFlags & MCI_OPEN_ELEMENT) &&
|
|
!(dwFlags & MCI_OPEN_ELEMENT_ID) &&
|
|
!SEGPTR_FREE(PTR_SEG_TO_LIN(mop16->lpstrElementName)))
|
|
FIXME(mci, "bad free line=%d\n", __LINE__);
|
|
if ((dwFlags & MCI_OPEN_ALIAS) &&
|
|
!SEGPTR_FREE(PTR_SEG_TO_LIN(mop16->lpstrAlias)))
|
|
FIXME(mci, "bad free line=%d\n", __LINE__);
|
|
|
|
if (!SEGPTR_FREE((LPVOID)((char*)mop16 - sizeof(LPMCI_OPEN_PARMSA))))
|
|
FIXME(mci, "bad free line=%d\n", __LINE__);
|
|
}
|
|
return 0;
|
|
/* 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_SETTIMECODE:*/
|
|
/* case MCI_SIGNAL:*/
|
|
case MCI_SPIN:
|
|
break;
|
|
case MCI_STATUS:
|
|
kept = TRUE;
|
|
switch (uDevType) {
|
|
case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STATUS_PARMS16); FIXME(mci, "NIY lpstrDevice\n");return -2;
|
|
case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STATUS_PARMS); break;*/FIXME(mci, "NIY vcr\n"); return -2;
|
|
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)PTR_SEG_TO_LIN(lParam);
|
|
LPMCI_SYSINFO_PARMSA msip32a = *(LPMCI_SYSINFO_PARMSA*)((char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSA));
|
|
|
|
if (msip16) {
|
|
msip16->dwCallback = msip32a->dwCallback;
|
|
memcpy(msip32a->lpstrReturn, PTR_SEG_TO_LIN(msip16->lpstrReturn), msip32a->dwRetSize);
|
|
if (!SEGPTR_FREE(msip16->lpstrReturn))
|
|
FIXME(mci, "bad free line=%d\n", __LINE__);
|
|
|
|
if (!SEGPTR_FREE((LPVOID)(lParam - sizeof(LPMCI_SYSINFO_PARMSA))))
|
|
FIXME(mci, "bad free line=%d\n", __LINE__);
|
|
} else {
|
|
return -2;
|
|
}
|
|
}
|
|
return 1;
|
|
/* case MCI_UNDO: */
|
|
case MCI_UNFREEZE:
|
|
break;
|
|
case MCI_UPDATE:
|
|
break;
|
|
case MCI_WHERE:
|
|
break;
|
|
case MCI_WINDOW:
|
|
/* FIXME: see map function */
|
|
break;
|
|
|
|
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(mci, "This is a hack\n");
|
|
return 0;
|
|
default:
|
|
FIXME(mci, "Map/Unmap internal error on msg=%s\n", MCI_CommandToString(wMsg));
|
|
return -1;
|
|
}
|
|
return MCI_MsgMapper32To16_Destroy((void*)lParam, size, kept);
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_SendCommand [internal]
|
|
*/
|
|
DWORD MCI_SendCommand(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
|
|
{
|
|
DWORD dwRet = MCIERR_DEVICE_NOT_INSTALLED;
|
|
|
|
if (!MCI_DevIDValid(wDevID)) {
|
|
dwRet = MCIERR_INVALID_DEVICE_ID;
|
|
} else {
|
|
MCIPROC proc = MCI_GetProc(MCI_GetDrv(wDevID)->modp.wType);
|
|
|
|
if (proc) {
|
|
dwRet = (*proc)(MCI_GetDrv(wDevID)->modp.wDeviceID,
|
|
MCI_GetDrv(wDevID)->hDrv,
|
|
wMsg, dwParam1, dwParam2);
|
|
} else if (MCI_GetDrv(wDevID)->hDrv) {
|
|
switch (DRIVER_GetType(MCI_GetDrv(wDevID)->hDrv)) {
|
|
case WINE_DI_TYPE_16:
|
|
{
|
|
int res;
|
|
|
|
switch (res = MCI_MapMsg32ATo16(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam1, &dwParam2)) {
|
|
case -1:
|
|
TRACE(mci, "Not handled yet (%s)\n", MCI_CommandToString(wMsg));
|
|
dwRet = MCIERR_DRIVER_INTERNAL;
|
|
break;
|
|
case -2:
|
|
TRACE(mci, "Problem mapping msg=%s from 16 to 32a\n", MCI_CommandToString(wMsg));
|
|
dwRet = MCIERR_OUT_OF_MEMORY;
|
|
break;
|
|
case 0:
|
|
case 1:
|
|
dwRet = SendDriverMessage16(MCI_GetDrv(wDevID)->hDrv, wMsg, dwParam1, dwParam2);
|
|
if (res)
|
|
MCI_UnMapMsg32ATo16(MCI_GetDrv(wDevID)->modp.wType, wMsg, dwParam1, dwParam2);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WINE_DI_TYPE_32:
|
|
dwRet = SendDriverMessage(MCI_GetDrv(wDevID)->hDrv, wMsg, dwParam1, dwParam2);
|
|
break;
|
|
default:
|
|
WARN(mci, "Unknown driver type=%u\n", DRIVER_GetType(MCI_GetDrv(wDevID)->hDrv));
|
|
dwRet = MCIERR_DRIVER_INTERNAL;
|
|
}
|
|
} else {
|
|
WARN(mci, "unknown device type=%04X !\n", MCI_GetDrv(wDevID)->modp.wType);
|
|
}
|
|
}
|
|
return dwRet;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_Open [internal]
|
|
*/
|
|
DWORD MCI_Open(DWORD dwParam, LPMCI_OPEN_PARMSA lpParms)
|
|
{
|
|
char strDevTyp[128];
|
|
UINT16 uDevType = 0;
|
|
UINT16 wDevID = MCI_FirstDevID();
|
|
DWORD dwRet;
|
|
|
|
TRACE(mci, "(%08lX, %p)\n", dwParam, lpParms);
|
|
if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
|
|
|
|
if ((dwParam & ~(MCI_OPEN_SHAREABLE|MCI_OPEN_ELEMENT|MCI_OPEN_ALIAS|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_NOTIFY|MCI_WAIT)) != 0) {
|
|
FIXME(mci, "unsupported yet dwFlags=%08lX\n",
|
|
(dwParam & ~(MCI_OPEN_SHAREABLE|MCI_OPEN_ELEMENT|MCI_OPEN_ALIAS|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_NOTIFY|MCI_WAIT)));
|
|
}
|
|
|
|
while (MCI_GetDrv(wDevID)->modp.wType != 0) {
|
|
wDevID = MCI_NextDevID(wDevID);
|
|
if (!MCI_DevIDValid(wDevID)) {
|
|
TRACE(mci, "MAXMCIDRIVERS reached !\n");
|
|
return MCIERR_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
TRACE(mci, "wDevID=%04X \n", wDevID);
|
|
memcpy(MCI_GetOpenDrv(wDevID), lpParms, sizeof(*lpParms));
|
|
|
|
strDevTyp[0] = 0;
|
|
|
|
if (dwParam & MCI_OPEN_ELEMENT) {
|
|
char* t;
|
|
|
|
TRACE(mci, "lpstrElementName='%s'\n", lpParms->lpstrElementName);
|
|
t = strrchr(lpParms->lpstrElementName, '.');
|
|
if (t) {
|
|
GetProfileStringA("mci extensions", t+1, "*", strDevTyp, sizeof(strDevTyp));
|
|
if (strcmp(strDevTyp, "*") == 0) {
|
|
TRACE(mci,"No [mci extensions] entry for %s found.\n", t);
|
|
return MCIERR_EXTENSION_NOT_FOUND;
|
|
}
|
|
TRACE(mci, "Extension %s is mapped to type %s\n", t, strDevTyp);
|
|
} else if (GetDriveTypeA(lpParms->lpstrElementName) == DRIVE_CDROM) {
|
|
/* FIXME: this will not work if several CDROM drives are installed on the machine */
|
|
strcpy(strDevTyp, "CDAUDIO");
|
|
} else {
|
|
return MCIERR_EXTENSION_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
if (dwParam & MCI_OPEN_ALIAS) {
|
|
TRACE(mci, "Alias='%s' !\n", lpParms->lpstrAlias);
|
|
/* FIXME is there any memory leak here ? */
|
|
MCI_GetOpenDrv(wDevID)->lpstrAlias = strdup(lpParms->lpstrAlias);
|
|
/* mplayer does allocate alias to CDAUDIO */
|
|
}
|
|
if (dwParam & MCI_OPEN_TYPE) {
|
|
if (dwParam & MCI_OPEN_TYPE_ID) {
|
|
#if 0
|
|
TRACE(mci, "Dev=%08lx!\n", (DWORD)lpParms->lpstrDeviceType);
|
|
uDevType = LOWORD((DWORD)lpParms->lpstrDeviceType);
|
|
MCI_GetOpenDrv(wDevID)->lpstrDeviceType = lpParms->lpstrDeviceType;
|
|
#endif
|
|
if (LOWORD((DWORD)lpParms->lpstrDeviceType) != MCI_DEVTYPE_CD_AUDIO) {
|
|
FIXME(mci, "MCI_OPEN_TYPE_ID is no longer properly supported\n");
|
|
}
|
|
uDevType = LOWORD((DWORD)lpParms->lpstrDeviceType);
|
|
} else {
|
|
if (lpParms->lpstrDeviceType == NULL)
|
|
return MCIERR_NULL_PARAMETER_BLOCK;
|
|
TRACE(mci, "Dev='%s' !\n", lpParms->lpstrDeviceType);
|
|
/* FIXME is there any memory leak here ? */
|
|
MCI_GetOpenDrv(wDevID)->lpstrDeviceType = strdup(lpParms->lpstrDeviceType);
|
|
strcpy(strDevTyp, lpParms->lpstrDeviceType);
|
|
}
|
|
}
|
|
|
|
if (uDevType == 0 && strDevTyp[0] != 0) {
|
|
CharUpperA(strDevTyp);
|
|
/* try Wine internal MCI drivers */
|
|
uDevType = MCI_GetDevType(strDevTyp);
|
|
if (uDevType == 0) { /* Nope, load external */
|
|
HDRVR hDrv;
|
|
MCI_OPEN_DRIVER_PARMSA modp;
|
|
|
|
modp.wDeviceID = wDevID;
|
|
modp.lpstrParams = NULL;
|
|
|
|
/* FIXME: this is a hack... some MCI drivers, while being open, call
|
|
* mciSetData, which lookup for non empty slots in MCI table list
|
|
* Unfortunatly, open slots are known when wType == 0...
|
|
* so use a dummy type, just to keep on going. May be wType == 0 is
|
|
* not the best solution to indicate empty slot in MCI drivers table
|
|
*/
|
|
MCI_GetDrv(wDevID)->modp.wType = MCI_DEVTYPE_CD_AUDIO;
|
|
hDrv = OpenDriverA(strDevTyp, "mci", (LPARAM)&modp);
|
|
|
|
if (!hDrv) {
|
|
FIXME(mci, "Couldn't load driver for type %s.\n", strDevTyp);
|
|
return MCIERR_DEVICE_NOT_INSTALLED;
|
|
}
|
|
uDevType = modp.wType;
|
|
MCI_GetDrv(wDevID)->hDrv = hDrv;
|
|
|
|
TRACE(mci, "Loaded driver %u (%s), type is %d\n", hDrv, strDevTyp, uDevType);
|
|
}
|
|
} else {
|
|
MCI_GetDrv(wDevID)->hDrv = 0;
|
|
}
|
|
|
|
MCI_GetDrv(wDevID)->modp.wType = uDevType;
|
|
MCI_GetDrv(wDevID)->modp.wDeviceID = 0; /* FIXME? for multiple devices */
|
|
|
|
lpParms->wDeviceID = wDevID;
|
|
|
|
TRACE(mci, "mcidev=%d, uDevType=%04X wDeviceID=%04X !\n",
|
|
wDevID, uDevType, lpParms->wDeviceID);
|
|
|
|
dwRet = MCI_SendCommand(wDevID, MCI_OPEN_DRIVER, dwParam, (DWORD)lpParms);
|
|
MCI_GetDrv(wDevID)->lpfnYieldProc = 0;
|
|
MCI_GetDrv(wDevID)->dwYieldData = 0;
|
|
MCI_GetDrv(wDevID)->hCreatorTask = GetCurrentTask();
|
|
|
|
if (dwRet == 0) {
|
|
/* only handled devices fall through */
|
|
TRACE(mci, "wDevID = %04X wDeviceID = %d dwRet = %ld\n", wDevID, lpParms->wDeviceID, dwRet);
|
|
} else {
|
|
TRACE(mci, "failed to open driver (MCI_OPEN_DRIVER msg) [%08lx], closing\n", dwRet);
|
|
MCI_GetDrv(wDevID)->modp.wType = 0;
|
|
}
|
|
if (dwParam & MCI_NOTIFY)
|
|
mciDriverNotify16(lpParms->dwCallback, wDevID, dwRet == 0 ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_Close [internal]
|
|
*/
|
|
DWORD MCI_Close(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
|
|
{
|
|
DWORD dwRet;
|
|
|
|
TRACE(mci, "(%04x, %08lX, %p)\n", wDevID, dwParam, lpParms);
|
|
|
|
if (wDevID == MCI_ALL_DEVICE_ID) {
|
|
FIXME(mci, "unhandled MCI_ALL_DEVICE_ID\n");
|
|
return MCIERR_CANNOT_USE_ALL;
|
|
}
|
|
|
|
dwRet = MCI_SendCommand(wDevID, MCI_CLOSE_DRIVER, dwParam, (DWORD)lpParms);
|
|
if (MCI_GetDrv(wDevID)->hDrv) {
|
|
#if 0
|
|
CloseDriver(MCI_GetDrv(wDevID)->hDrv, 0, 0);
|
|
#endif
|
|
}
|
|
MCI_GetDrv(wDevID)->modp.wType = 0;
|
|
|
|
if (dwParam & MCI_NOTIFY)
|
|
mciDriverNotify16(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;
|
|
|
|
if (dstSize <= strlen(lpSrcStr)) {
|
|
lstrcpynA(lpDstStr, lpSrcStr, dstSize - 1);
|
|
ret = MCIERR_PARAM_OVERFLOW;
|
|
} else {
|
|
strcpy(lpDstStr, lpSrcStr);
|
|
ret = 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_Sysinfo [internal]
|
|
*/
|
|
DWORD MCI_SysInfo(UINT uDevID, DWORD dwFlags, LPMCI_SYSINFO_PARMSA lpParms)
|
|
{
|
|
DWORD ret = MCIERR_INVALID_DEVICE_ID;
|
|
|
|
if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
|
|
|
|
TRACE(mci, "(%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:
|
|
{
|
|
DWORD cnt = 0;
|
|
WORD i;
|
|
|
|
if (lpParms->wDeviceType < MCI_DEVTYPE_FIRST || lpParms->wDeviceType > MCI_DEVTYPE_LAST) {
|
|
if (dwFlags & MCI_SYSINFO_OPEN) {
|
|
TRACE(mci, "MCI_SYSINFO_QUANTITY: # of open MCI drivers\n");
|
|
for (i = 0; i < MAXMCIDRIVERS; i++) {
|
|
if (mciDrv[i].modp.wType != 0) cnt++;
|
|
}
|
|
} else {
|
|
TRACE(mci, "MCI_SYSINFO_QUANTITY: # of installed MCI drivers\n");
|
|
cnt = mciInstalledCount;
|
|
}
|
|
} else {
|
|
if (dwFlags & MCI_SYSINFO_OPEN) {
|
|
TRACE(mci, "MCI_SYSINFO_QUANTITY: # of open MCI drivers of type %u\n", lpParms->wDeviceType);
|
|
for (i = 0; i < MAXMCIDRIVERS; i++) {
|
|
if (mciDrv[i].modp.wType == lpParms->wDeviceType) cnt++;
|
|
}
|
|
} else {
|
|
TRACE(mci, "MCI_SYSINFO_QUANTITY: # of installed MCI drivers of type %u\n", lpParms->wDeviceType);
|
|
FIXME(mci, "Don't know how to get # of MCI devices of a given type\n");
|
|
cnt = 1;
|
|
}
|
|
}
|
|
*(DWORD*)lpParms->lpstrReturn = cnt;
|
|
}
|
|
TRACE(mci, "(%ld) => '%ld'\n", lpParms->dwNumber, *(DWORD*)lpParms->lpstrReturn);
|
|
ret = 0;
|
|
break;
|
|
case MCI_SYSINFO_INSTALLNAME:
|
|
TRACE(mci, "MCI_SYSINFO_INSTALLNAME \n");
|
|
if (MCI_DevIDValid(uDevID)) {
|
|
LPCSTR str = MCI_GetDevTypeString(MCI_GetDrv(uDevID)->modp.wType);
|
|
ret = MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, str);
|
|
} else {
|
|
*lpParms->lpstrReturn = 0;
|
|
ret = MCIERR_INVALID_DEVICE_ID;
|
|
}
|
|
TRACE(mci, "(%ld) => '%s'\n", lpParms->dwNumber, lpParms->lpstrReturn);
|
|
break;
|
|
case MCI_SYSINFO_NAME:
|
|
TRACE(mci, "MCI_SYSINFO_NAME\n");
|
|
if (dwFlags & MCI_SYSINFO_OPEN) {
|
|
FIXME(mci, "Don't handle MCI_SYSINFO_NAME|MCI_SYSINFO_OPEN (yet)\n");
|
|
ret = MCIERR_UNRECOGNIZED_COMMAND;
|
|
} else if (lpParms->dwNumber > mciInstalledCount) {
|
|
ret = MCIERR_OUTOFRANGE;
|
|
} else {
|
|
DWORD count = lpParms->dwNumber;
|
|
LPSTR ptr = lpmciInstallNames;
|
|
|
|
while (--count > 0) ptr += strlen(ptr) + 1;
|
|
ret = MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, ptr);
|
|
}
|
|
TRACE(mci, "(%ld) => '%s'\n", lpParms->dwNumber, lpParms->lpstrReturn);
|
|
break;
|
|
default:
|
|
TRACE(mci, "Unsupported flag value=%08lx\n", dwFlags);
|
|
ret = MCIERR_UNRECOGNIZED_COMMAND;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
struct SCA {
|
|
UINT wDevID;
|
|
UINT wMsg;
|
|
DWORD dwParam1;
|
|
DWORD dwParam2;
|
|
BOOL allocatedCopy;
|
|
};
|
|
|
|
DWORD WINAPI mciSendCommandA(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2);
|
|
|
|
/**************************************************************************
|
|
* MCI_SCAStarter [internal]
|
|
*/
|
|
static DWORD WINAPI MCI_SCAStarter(LPVOID arg)
|
|
{
|
|
struct SCA* sca = (struct SCA*)arg;
|
|
DWORD ret;
|
|
|
|
TRACE(mci, "In thread before async command (%08x,%s,%08lx,%08lx)\n",
|
|
sca->wDevID, MCI_CommandToString(sca->wMsg), sca->dwParam1, sca->dwParam2);
|
|
ret = mciSendCommandA(sca->wDevID, sca->wMsg, sca->dwParam1 | MCI_WAIT, sca->dwParam2);
|
|
TRACE(mci, "In thread after async command (%08x,%s,%08lx,%08lx)\n",
|
|
sca->wDevID, MCI_CommandToString(sca->wMsg), sca->dwParam1, sca->dwParam2);
|
|
if (sca->allocatedCopy)
|
|
HeapFree(GetProcessHeap(), 0, (LPVOID)sca->dwParam2);
|
|
HeapFree(GetProcessHeap(), 0, sca);
|
|
ExitThread(ret);
|
|
WARN(mci, "Should not happen ? what's wrong \n");
|
|
/* should not go after this point */
|
|
return ret;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* MCI_SendCommandAsync [internal]
|
|
*/
|
|
DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1, DWORD dwParam2, UINT size)
|
|
{
|
|
struct SCA* sca = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA));
|
|
|
|
if (sca == 0)
|
|
return MCIERR_OUT_OF_MEMORY;
|
|
|
|
sca->wDevID = wDevID;
|
|
sca->wMsg = wMsg;
|
|
sca->dwParam1 = dwParam1;
|
|
|
|
if (size) {
|
|
sca->dwParam2 = (DWORD)HeapAlloc(GetProcessHeap(), 0, size);
|
|
if (sca->dwParam2 == 0) {
|
|
HeapFree(GetProcessHeap(), 0, sca);
|
|
return MCIERR_OUT_OF_MEMORY;
|
|
}
|
|
sca->allocatedCopy = TRUE;
|
|
/* copy structure passed by program in dwParam2 to be sure
|
|
* we can still use it whatever the program does
|
|
*/
|
|
memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size);
|
|
} else {
|
|
sca->dwParam2 = dwParam2;
|
|
sca->allocatedCopy = FALSE;
|
|
}
|
|
|
|
if (CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL) == 0) {
|
|
WARN(mci, "Couldn't allocate thread for async command handling, sending synchonously\n");
|
|
return MCI_SCAStarter(&sca);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* 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 read of them.
|
|
*/
|
|
LRESULT MCI_CleanUp(LRESULT dwRet, UINT wMsg, DWORD dwParam2, BOOL bIs32)
|
|
{
|
|
switch (wMsg) {
|
|
case MCI_GETDEVCAPS:
|
|
switch (dwRet & 0xFFFF0000ul) {
|
|
case 0:
|
|
break;
|
|
case MCI_RESOURCE_RETURNED:
|
|
case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER:
|
|
case MCI_COLONIZED3_RETURN:
|
|
case MCI_COLONIZED4_RETURN:
|
|
case MCI_INTEGER_RETURNED:
|
|
{
|
|
LPMCI_GETDEVCAPS_PARMS lmgp = (LPMCI_GETDEVCAPS_PARMS)(bIs32 ? (void*)dwParam2 : PTR_SEG_TO_LIN(dwParam2));
|
|
|
|
dwRet = LOWORD(dwRet);
|
|
TRACE(mci, "Changing %08lx to %08lx\n", lmgp->dwReturn, (DWORD)LOWORD(lmgp->dwReturn));
|
|
|
|
lmgp->dwReturn = LOWORD(lmgp->dwReturn);
|
|
}
|
|
break;
|
|
default:
|
|
FIXME(mci, "Unsupported value for hiword (%04x) returned by DriverProc\n", HIWORD(dwRet));
|
|
}
|
|
break;
|
|
case MCI_STATUS:
|
|
switch (dwRet & 0xFFFF0000ul) {
|
|
case 0:
|
|
break;
|
|
case MCI_RESOURCE_RETURNED:
|
|
case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER:
|
|
case MCI_COLONIZED3_RETURN:
|
|
case MCI_COLONIZED4_RETURN:
|
|
case MCI_INTEGER_RETURNED:
|
|
{
|
|
LPMCI_STATUS_PARMS lsp = (LPMCI_STATUS_PARMS)(bIs32 ? (void*)dwParam2 : PTR_SEG_TO_LIN(dwParam2));
|
|
|
|
dwRet = LOWORD(dwRet);
|
|
TRACE(mci, "Changing %08lx to %08lx\n", lsp->dwReturn,(DWORD) LOWORD(lsp->dwReturn));
|
|
lsp->dwReturn = LOWORD(lsp->dwReturn);
|
|
}
|
|
break;
|
|
default:
|
|
FIXME(mci, "Unsupported value for hiword (%04x) returned by DriverProc\n", HIWORD(dwRet));
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return dwRet;
|
|
}
|
|
|