wine/dlls/winmm/mci.c
Eric Pouech 66b4468bd4 Split driver functions into USER (16 bit part) and WINMM (32 bit part).
Fixed some bugs in 16 bit part as well.
Now correctly parsing the system.ini extra parameters.
2000-12-13 02:07:40 +00:00

2554 lines
74 KiB
C

/* -*- tab-width: 8; c-basic-offset: 4 -*- */
/*
* MCI internal functions
*
* Copyright 1998/1999 Eric Pouech
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "heap.h"
#include "winemm.h"
#include "selectors.h"
#include "digitalv.h"
#include "wine/winbase16.h"
#include "debugtools.h"
#include "winreg.h"
DEFAULT_DEBUG_CHANNEL(mci);
static int MCI_InstalledCount;
static LPSTR MCI_lpInstallNames = NULL;
typedef enum {
MCI_MAP_NOMEM, /* ko, memory problem */
MCI_MAP_MSGERROR, /* ko, unknown message */
MCI_MAP_OK, /* ok, no memory allocated. to be sent to the proc. */
MCI_MAP_OKMEM, /* ok, some memory allocated, need to call UnMapMsg. to be sent to the proc. */
} MCI_MapType;
static MCI_MapType MCI_MapMsg16To32A (WORD uDevType, WORD wMsg, DWORD* lParam);
static MCI_MapType MCI_UnMapMsg16To32A(WORD uDevType, WORD wMsg, DWORD lParam);
static MCI_MapType MCI_MapMsg32ATo16 (WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD* lParam);
static MCI_MapType MCI_UnMapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD lParam);
/* First MCI valid device ID (0 means error) */
#define MCI_MAGIC 0x0001
/**************************************************************************
* MCI_GetDriver [internal]
*/
LPWINE_MCIDRIVER MCI_GetDriver(UINT16 wDevID)
{
LPWINE_MCIDRIVER wmd = 0;
LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
EnterCriticalSection(&iData->cs);
for (wmd = iData->lpMciDrvs; wmd; wmd = wmd->lpNext) {
if (wmd->wDeviceID == wDevID)
break;
}
LeaveCriticalSection(&iData->cs);
return wmd;
}
/**************************************************************************
* MCI_GetDriverFromString [internal]
*/
UINT MCI_GetDriverFromString(LPCSTR lpstrName)
{
LPWINE_MCIDRIVER wmd;
LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
UINT ret = 0;
if (!lpstrName)
return 0;
if (!lstrcmpiA(lpstrName, "ALL"))
return MCI_ALL_DEVICE_ID;
EnterCriticalSection(&iData->cs);
for (wmd = iData->lpMciDrvs; wmd; wmd = wmd->lpNext) {
if (wmd->lpstrElementName && strcmp(wmd->lpstrElementName, lpstrName) == 0) {
ret = wmd->wDeviceID;
break;
}
if (wmd->lpstrDeviceType && strcmp(wmd->lpstrDeviceType, lpstrName) == 0) {
ret = wmd->wDeviceID;
break;
}
if (wmd->lpstrAlias && strcmp(wmd->lpstrAlias, lpstrName) == 0) {
ret = wmd->wDeviceID;
break;
}
}
LeaveCriticalSection(&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;
if ((tmp = strrchr(fileName, '.'))) {
GetProfileStringA("mci extensions", tmp + 1, "*", buf, len);
if (strcmp(buf, "*") != 0) {
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 {
HANDLE hMem;
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;
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 [hMem=%08x devType=%d]\n",
uTbl, S_MciCmdTable[uTbl].hMem, S_MciCmdTable[uTbl].uDevType);
if (uTbl >= MAX_MCICMDTABLE || !S_MciCmdTable[uTbl].hMem || !S_MciCmdTable[uTbl].lpTable)
return FALSE;
lmem = S_MciCmdTable[uTbl].lpTable;
do {
do {
str = lmem;
lmem += strlen(lmem) + 1;
flg = *(LPDWORD)lmem;
eid = *(LPWORD)(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 = *(LPDWORD)lmem;
eid = *(LPWORD)(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;
}
static UINT MCI_SetCommandTable(LPWINE_MM_IDATA iData, HANDLE hMem, UINT uDevType);
/**************************************************************************
* MCI_GetCommandTable [internal]
*/
static UINT MCI_GetCommandTable(LPWINE_MM_IDATA iData, UINT uDevType)
{
UINT uTbl;
char buf[32];
LPSTR str = NULL;
/* first look up existing for existing devType */
for (uTbl = 0; uTbl < MAX_MCICMDTABLE; uTbl++) {
if (S_MciCmdTable[uTbl].hMem && S_MciCmdTable[uTbl].uDevType == uDevType)
return uTbl;
}
/* well try to load id */
if (uDevType >= MCI_DEVTYPE_FIRST && uDevType <= MCI_DEVTYPE_LAST) {
if (LoadStringA(iData->hWinMM32Instance, uDevType, buf, sizeof(buf))) {
str = buf;
}
} else if (uDevType == 0) {
str = "CORE";
}
uTbl = MCI_NO_COMMAND_TABLE;
if (str) {
HRSRC hRsrc = FindResourceA(iData->hWinMM32Instance, str, (LPCSTR)RT_RCDATAA);
HANDLE hMem = 0;
if (hRsrc) hMem = LoadResource(iData->hWinMM32Instance, hRsrc);
if (hMem) {
uTbl = MCI_SetCommandTable(iData, hMem, uDevType);
} else {
WARN("No command table found in resource %04x[%s]\n",
iData->hWinMM32Instance, str);
}
}
TRACE("=> %d\n", uTbl);
return uTbl;
}
/**************************************************************************
* MCI_SetCommandTable [internal]
*/
static UINT MCI_SetCommandTable(LPWINE_MM_IDATA iData, HANDLE hMem,
UINT uDevType)
{
int uTbl;
static BOOL bInitDone = FALSE;
/* <HACK>
* The CORE command table must be loaded first, so that MCI_GetCommandTable()
* can be called with 0 as a uDevType to retrieve it.
* </HACK>
*/
if (!bInitDone) {
bInitDone = TRUE;
for (uTbl = 0; uTbl < MAX_MCICMDTABLE; uTbl++) {
S_MciCmdTable[uTbl].hMem = 0;
}
MCI_GetCommandTable(iData, 0);
}
for (uTbl = 0; uTbl < MAX_MCICMDTABLE; uTbl++) {
if (S_MciCmdTable[uTbl].hMem == 0) {
LPCSTR lmem, str;
WORD eid;
WORD count;
S_MciCmdTable[uTbl].hMem = hMem;
S_MciCmdTable[uTbl].uDevType = uDevType;
S_MciCmdTable[uTbl].lpTable = LockResource(hMem);
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 = *(LPWORD)(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 = *(LPWORD)(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].hMem)
return FALSE;
FreeResource(S_MciCmdTable[uTbl].hMem);
S_MciCmdTable[uTbl].hMem = 0;
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_MM_IDATA iData, 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(&iData->cs);
for (tmp = &iData->lpMciDrvs; *tmp; tmp = &(*tmp)->lpNext) {
if (*tmp == wmd) {
*tmp = wmd->lpNext;
break;
}
}
LeaveCriticalSection(&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 {
MCI_MapType res;
switch (res = MCI_MapMsg32ATo16(0, MCI_OPEN_DRIVER, 0, &lp)) {
case MCI_MAP_MSGERROR:
TRACE("Not handled yet (MCI_OPEN_DRIVER)\n");
break;
case MCI_MAP_NOMEM:
TRACE("Problem mapping msg=MCI_OPEN_DRIVER from 32a to 16\n");
break;
case MCI_MAP_OK:
case MCI_MAP_OKMEM:
if ((wmd->hDriver = OpenDriverA(drvTyp, "mci", lp)))
wmd->bIs32 = FALSE;
if (res == MCI_MAP_OKMEM)
MCI_UnMapMsg32ATo16(0, MCI_OPEN_DRIVER, 0, lp);
break;
}
}
return (wmd->bIs32 == 0xFFFF) ? FALSE : TRUE;
}
/**************************************************************************
* MCI_LoadMciDriver [internal]
*/
static DWORD MCI_LoadMciDriver(LPWINE_MM_IDATA iData, LPCSTR _strDevTyp,
LPWINE_MCIDRIVER* lpwmd)
{
LPSTR strDevTyp = CharUpperA(HEAP_strdupA(GetProcessHeap(), 0, _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->hCreatorTask = GetCurrentTask();
EnterCriticalSection(&iData->cs);
/* wmd must be inserted in list before sending opening the driver, coz' it
* may want to lookup at wDevID
*/
wmd->lpNext = iData->lpMciDrvs;
iData->lpMciDrvs = wmd;
for (modp.wDeviceID = MCI_MAGIC;
MCI_GetDriver(modp.wDeviceID) != 0;
modp.wDeviceID++);
wmd->wDeviceID = modp.wDeviceID;
LeaveCriticalSection(&iData->cs);
TRACE("wDevID=%04X \n", modp.wDeviceID);
modp.lpstrParams = NULL;
if (!MCI_OpenMciDriver(wmd, strDevTyp, (LPARAM)&modp)) {
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 %x (%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(iData, 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 = HEAP_strdupA(GetProcessHeap(), 0,
lpParms->lpstrElementName);
if (dwParam & MCI_OPEN_ALIAS)
wmd->lpstrAlias = HEAP_strdupA(GetProcessHeap(), 0, 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].hMem == 0)
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 (strcmp(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' && *(LPWORD)(lpCmd + 1 + sizeof(DWORD)) == MCI_RETURN) {
return *(LPDWORD)(lpCmd + 1);
}
return 0L;
}
/**************************************************************************
* MCI_GetMessage [internal]
*/
static WORD MCI_GetMessage(LPCSTR lpCmd)
{
return (WORD)*(LPDWORD)(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;
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 = *(LPDWORD)lmem;
eid = *(LPWORD)(lmem + sizeof(DWORD));
lmem += sizeof(DWORD) + sizeof(WORD);
/* EPP TRACE("\tcmd='%s' inCst=%s\n", str, inCst ? "Y" : "N"); */
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;
if (*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");
}
/* exit inside while loop */
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");
}
}
} while (eid != MCI_END_COMMAND);
if (!found) {
TRACE("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(LPWINE_MM_IDATA iData, DWORD dwRet,
LPWINE_MCIDRIVER wmd, LPCSTR lpCmd, LPDWORD data,
LPSTR lpstrRet, UINT uRetLen)
{
if (lpstrRet) {
switch (MCI_GetReturnType(lpCmd)) {
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(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 [MMSYSTEM.702][WINMM.51]
*/
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];
LPCSTR lpCmd = 0;
LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
BOOL bAutoOpen = FALSE;
TRACE("('%s', %p, %d, %X)\n", lpstrCommand, lpstrRet, uRetLen, hwndCallback);
/* format is <command> <device> <optargs> */
if (!(verb = HEAP_strdupA(GetProcessHeap(), 0, lpstrCommand)))
return MCIERR_OUT_OF_MEMORY;
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 (!strcasecmp(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 = CharUpperA(HEAP_strdupA(GetProcessHeap(), 0, devType));
} else if (strchr(dev, '.') == NULL) {
tmp = strchr(dev,' ');
if (tmp) *tmp = '\0';
data[2] = (DWORD)dev;
devType = CharUpperA(HEAP_strdupA(GetProcessHeap(), 0, 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 = CharUpperA(HEAP_strdupA(GetProcessHeap(), 0, 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 = CharUpperA(HEAP_strdupA(GetProcessHeap(), 0, buf));
}
dwFlags |= MCI_OPEN_ELEMENT;
data[3] = (DWORD)dev;
}
dwRet = MCI_LoadMciDriver(iData, devType, &wmd);
HeapFree(GetProcessHeap(), 0, devType);
if (dwRet) {
MCI_UnLoadMciDriver(iData, 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 */
/* try the device specific command table */
if (wmd) lpCmd = MCI_FindCommand(wmd->uSpecificCmdTable, verb);
/* try the type specific command table */
if (!lpCmd) {
if (wmd && wmd->uTypeCmdTable == MCI_COMMAND_TABLE_NOT_LOADED)
wmd->uTypeCmdTable = MCI_GetCommandTable(iData, wmd->wType);
if (wmd && wmd->uTypeCmdTable != MCI_NO_COMMAND_TABLE)
lpCmd = MCI_FindCommand(wmd->uTypeCmdTable, verb);
}
/* try core command table */
if (!lpCmd) lpCmd = MCI_FindCommand(MCI_GetCommandTable(iData, 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 (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';
#define STR_OF(_x) (IsBadReadPtr((char*)_x,1)?"?":(char*)(_x))
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], STR_OF(data[0]), data[1], STR_OF(data[1]),
data[2], STR_OF(data[2]), data[3], STR_OF(data[3]),
data[4], STR_OF(data[4]), data[5], STR_OF(data[5]));
#undef STR_OF
if (strcmp(verb, "open") == 0) {
if ((dwRet = MCI_FinishOpen(wmd, (LPMCI_OPEN_PARMSA)data, dwFlags)))
MCI_UnLoadMciDriver(iData, 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);
if (dwRet) goto errCleanUp;
dwRet = MCI_HandleReturnValues(iData, dwRet, wmd, lpCmd, data, lpstrRet, uRetLen);
TRACE("=> 2/ %lx (%s)\n", dwRet, lpstrRet);
errCleanUp:
HeapFree(GetProcessHeap(), 0, verb);
return dwRet;
}
/**************************************************************************
* mciSendStringW [WINMM.52]
*/
DWORD WINAPI mciSendStringW(LPCWSTR lpwstrCommand, LPSTR lpstrRet,
UINT uRetLen, HWND hwndCallback)
{
LPSTR lpstrCommand;
UINT ret;
/* FIXME: is there something to do with lpstrReturnString ? */
lpstrCommand = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrCommand);
ret = mciSendStringA(lpstrCommand, lpstrRet, uRetLen, hwndCallback);
HeapFree(GetProcessHeap(), 0, lpstrCommand);
return ret;
}
/**************************************************************************
* mciSendString16 [MMSYSTEM.702]
*/
DWORD WINAPI mciSendString16(LPCSTR lpstrCommand, LPSTR lpstrRet,
UINT16 uRetLen, HWND16 hwndCallback)
{
return mciSendStringA(lpstrCommand, lpstrRet, uRetLen, hwndCallback);
}
/**************************************************************************
* mciExecute [WINMM.38]
*/
DWORD WINAPI mciExecute(LPCSTR lpstrCommand)
{
char strRet[256];
DWORD ret;
TRACE("(%s)!\n", lpstrCommand);
ret = mciSendString16(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 [MMSYSTEM.705]
*/
UINT16 WINAPI mciLoadCommandResource16(HANDLE16 hInst, LPCSTR resname, UINT16 type)
{
HRSRC hRsrc = 0;
HGLOBAL hMem;
UINT16 ret = MCI_NO_COMMAND_TABLE;
LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
TRACE("(%04x, %s, %d)!\n", hInst, resname, type);
/* if file exists "resname.mci", 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) {
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);
}
}
if (!(hRsrc = FindResourceA(hInst, resname, (LPCSTR)RT_RCDATAA))) {
WARN("No command table found in resource\n");
} else if ((hMem = LoadResource(hInst, hRsrc))) {
ret = MCI_SetCommandTable(iData, hMem, type);
} else {
WARN("Couldn't load resource.\n");
}
TRACE("=> %04x\n", ret);
return ret;
}
/**************************************************************************
* mciFreeCommandResource [MMSYSTEM.713]
*/
BOOL16 WINAPI mciFreeCommandResource16(UINT16 uTable)
{
TRACE("(%04x)!\n", uTable);
return MCI_DeleteCommandTable(uTable);
}
/**************************************************************************
* mciLoadCommandResource [WINMM.48]
*
* Strangely, this function only exists as an UNICODE one.
*/
UINT WINAPI mciLoadCommandResource(HINSTANCE hinst, LPCWSTR resNameW, UINT type)
{
LPSTR resNameA;
UINT ret;
TRACE("(%04x, %s, %d)!\n", hinst, debugstr_w(resNameW), type);
resNameA = HEAP_strdupWtoA(GetProcessHeap(), 0, resNameW);
ret = mciLoadCommandResource16(hinst, resNameA, type);
HeapFree(GetProcessHeap(), 0, resNameA);
return ret;
}
/**************************************************************************
* mciFreeCommandResource [WINMM.39]
*/
BOOL WINAPI mciFreeCommandResource(UINT uTable)
{
TRACE("(%08x)!\n", uTable);
return mciFreeCommandResource16(uTable);
}
/**************************************************************************
* MCI_MapMsg16To32A [internal]
*/
static MCI_MapType MCI_MapMsg16To32A(WORD uDevType, WORD wMsg, DWORD* lParam)
{
if (*lParam == 0)
return MCI_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)PTR_SEG_TO_LIN(*lParam);
return MCI_MAP_OK;
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("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 = PTR_SEG_TO_LIN(*lParam);
if (mbp32) {
mbp32->dwCallback = mbp16->dwCallback;
mbp32->nVirtKey = mbp16->nVirtKey;
mbp32->hwndBreak = mbp16->hwndBreak;
} else {
return MCI_MAP_NOMEM;
}
*lParam = (DWORD)mbp32;
}
return MCI_MAP_OKMEM;
case MCI_ESCAPE:
{
LPMCI_VD_ESCAPE_PARMSA mvep32a = HeapAlloc(GetProcessHeap(), 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 MCI_MAP_NOMEM;
}
*lParam = (DWORD)mvep32a;
}
return MCI_MAP_OKMEM;
case MCI_INFO:
{
LPMCI_INFO_PARMSA mip32a = HeapAlloc(GetProcessHeap(), 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 MCI_MAP_NOMEM;
}
*lParam = (DWORD)mip32a;
}
return MCI_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 = 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 MCI_MAP_NOMEM;
}
*lParam = (DWORD)mop32a;
}
return MCI_MAP_OKMEM;
case MCI_SYSINFO:
{
LPMCI_SYSINFO_PARMSA msip32a = HeapAlloc(GetProcessHeap(), 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 MCI_MAP_NOMEM;
}
*lParam = (DWORD)msip32a;
}
return MCI_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 MCI_MAP_OK;
default:
WARN("Don't know how to map msg=%s\n", MCI_MessageToString(wMsg));
}
return MCI_MAP_MSGERROR;
}
/**************************************************************************
* MCI_UnMapMsg16To32A [internal]
*/
static MCI_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 MCI_MAP_OK;
case MCI_WINDOW:
/* FIXME ?? see Map function */
return MCI_MAP_OK;
case MCI_BREAK:
case MCI_ESCAPE:
case MCI_INFO:
case MCI_SYSINFO:
HeapFree(GetProcessHeap(), 0, (LPVOID)lParam);
return MCI_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 MCI_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 MCI_MAP_OK;
default:
FIXME("Map/Unmap internal error on msg=%s\n", MCI_MessageToString(wMsg));
}
return MCI_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 MCI_MapType MCI_MsgMapper32To16_Create(void** ptr, int size16, DWORD map, BOOLEAN keep)
{
void* lp = SEGPTR_ALLOC((keep ? sizeof(void**) : 0) + size16);
LPBYTE p16, p32;
if (!lp) {
return MCI_MAP_NOMEM;
}
p32 = (LPBYTE)(*ptr);
if (keep) {
*(void**)lp = *ptr;
p16 = (LPBYTE)lp + sizeof(void**);
*ptr = (char*)SEGPTR_GET(lp) + sizeof(void**);
} else {
p16 = lp;
*ptr = (void*)SEGPTR_GET(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 = ( INT16)*( LPINT16)p32; p16 += 2; p32 += 4; size16 -= 2; break;
case 0x2: *(LPUINT16)p16 = (UINT16)*(LPUINT16)p32; p16 += 2; p32 += 4; size16 -= 2; break;
case 0x6: *(LPDWORD)p16 = 0; p16 += 4; p32 += 4; size16 -= 4; break;
case 0x7: *(LPDWORD)p16 = SEGPTR_GET(SEGPTR_STRDUP(*(LPSTR*)p32));p16 += 4; p32 += 4; size16 -= 4; 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 MCI_MAP_OKMEM;
}
/**************************************************************************
* MCI_MsgMapper32To16_Destroy [internal]
*
* Helper for MCI_UnMapMsg32ATo16.
*/
static MCI_MapType MCI_MsgMapper32To16_Destroy(void* ptr, int size16, DWORD map, BOOLEAN kept)
{
if (ptr) {
void* msg16 = PTR_SEG_TO_LIN(ptr);
void* alloc;
LPBYTE p32, p16;
unsigned nibble;
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 += 2; p32 += 4; size16 -= 2; break;
case 0x2: *(LPUINT)p32 = *(LPUINT16)p16; p16 += 2; p32 += 4; size16 -= 2; break;
case 0x6: p16 += 4; p32 += 4; size16 -= 4; break;
case 0x7: strcpy(*(LPSTR*)p32, PTR_SEG_TO_LIN(*(DWORD*)p16));
if (!SEGPTR_FREE(PTR_SEG_TO_LIN(*(DWORD*)p16))) {
FIXME("bad free line=%d\n", __LINE__);
}
p16 += 4; p32 += 4; size16 -= 4; 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;
}
if (!SEGPTR_FREE(alloc)) {
FIXME("bad free line=%d\n", __LINE__);
}
}
return MCI_MAP_OK;
}
/**************************************************************************
* MCI_MapMsg32ATo16 [internal]
*
* Map a 32-A bit MCI message to a 16 bit MCI message.
*/
static MCI_MapType MCI_MapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD* lParam)
{
int size;
BOOLEAN keep = FALSE;
DWORD map = 0;
if (*lParam == 0)
return MCI_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:
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("NIY vcr\n"); return MCI_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);
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 MCI_MAP_NOMEM;
}
*lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_INFO_PARMSA);
}
return MCI_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 = 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 MCI_MAP_NOMEM;
}
*lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_OPEN_PARMSA);
}
return MCI_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 MCI_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 MCI_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 MCI_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_SETTIMECODE:*/
/* case MCI_SIGNAL:*/
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 thru 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 MCI_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 MCI_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);
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 MCI_MAP_NOMEM;
}
*lParam = (LPARAM)SEGPTR_GET(ptr) + sizeof(LPMCI_SYSINFO_PARMSA);
}
return MCI_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_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:
return MCI_MAP_OK;
default:
WARN("Don't know how to map msg=%s\n", MCI_MessageToString(wMsg));
return MCI_MAP_MSGERROR;
}
return MCI_MsgMapper32To16_Create((void**)lParam, size, map, keep);
}
/**************************************************************************
* MCI_UnMapMsg32ATo16 [internal]
*/
static MCI_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:
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("bad free line=%d\n", __LINE__);
if (!SEGPTR_FREE((char*)mip16 - sizeof(LPMCI_INFO_PARMSA)))
FIXME("bad free line=%d\n", __LINE__);
}
return MCI_MAP_OK;
/* 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("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("bad free line=%d\n", __LINE__);
if ((dwFlags & MCI_OPEN_ALIAS) &&
!SEGPTR_FREE(PTR_SEG_TO_LIN(mop16->lpstrAlias)))
FIXME("bad free line=%d\n", __LINE__);
if (!SEGPTR_FREE((char*)mop16 - sizeof(LPMCI_OPEN_PARMSA)))
FIXME("bad free line=%d\n", __LINE__);
}
return MCI_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_SETTIMECODE:*/
/* case MCI_SIGNAL:*/
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)PTR_SEG_TO_LIN(lParam);
LPMCI_DGV_STATUS_PARMSA mdsp32a = *(LPMCI_DGV_STATUS_PARMSA*)((char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA));
if (mdsp16) {
mdsp32a->dwReturn = mdsp16->dwReturn;
if (dwFlags & MCI_DGV_STATUS_DISKSPACE) {
TRACE("MCI_STATUS (DGV) lpstrDrive=%p\n", mdsp16->lpstrDrive);
TRACE("MCI_STATUS (DGV) lpstrDrive=%s\n", (LPSTR)PTR_SEG_TO_LIN(mdsp16->lpstrDrive));
/* FIXME: see map function */
strcpy(mdsp32a->lpstrDrive, (LPSTR)PTR_SEG_TO_LIN(mdsp16->lpstrDrive));
}
if (!SEGPTR_FREE((char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA)))
FIXME("bad free line=%d\n", __LINE__);
} else {
return MCI_MAP_NOMEM;
}
}
return MCI_MAP_OKMEM;
case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STATUS_PARMS); break;*/FIXME("NIY vcr\n"); return MCI_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)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(PTR_SEG_TO_LIN(msip16->lpstrReturn)))
FIXME("bad free line=%d\n", __LINE__);
if (!SEGPTR_FREE((char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSA)))
FIXME("bad free line=%d\n", __LINE__);
} else {
return MCI_MAP_NOMEM;
}
}
return MCI_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_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 MCI_MAP_OK;
default:
FIXME("Map/Unmap internal error on msg=%s\n", MCI_MessageToString(wMsg));
return MCI_MAP_MSGERROR;
}
return MCI_MsgMapper32To16_Destroy((void*)lParam, size, map, kept);
}
/**************************************************************************
* MCI_SendCommandFrom32 [internal]
*/
DWORD MCI_SendCommandFrom32(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD 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 {
MCI_MapType res;
switch (res = MCI_MapMsg32ATo16(wmd->wType, wMsg, dwParam1, &dwParam2)) {
case MCI_MAP_MSGERROR:
TRACE("Not handled yet (%s)\n", MCI_MessageToString(wMsg));
dwRet = MCIERR_DRIVER_INTERNAL;
break;
case MCI_MAP_NOMEM:
TRACE("Problem mapping msg=%s from 32a to 16\n", MCI_MessageToString(wMsg));
dwRet = MCIERR_OUT_OF_MEMORY;
break;
case MCI_MAP_OK:
case MCI_MAP_OKMEM:
dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2);
if (res == MCI_MAP_OKMEM)
MCI_UnMapMsg32ATo16(wmd->wType, wMsg, dwParam1, dwParam2);
break;
}
}
}
return dwRet;
}
/**************************************************************************
* MCI_SendCommandFrom16 [internal]
*/
DWORD MCI_SendCommandFrom16(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2)
{
DWORD dwRet = MCIERR_INVALID_DEVICE_ID;
LPWINE_MCIDRIVER wmd = MCI_GetDriver(wDevID);
if (wmd) {
dwRet = MCIERR_INVALID_DEVICE_ID;
if (wmd->bIs32) {
MCI_MapType res;
switch (res = MCI_MapMsg16To32A(wmd->wType, wMsg, &dwParam2)) {
case MCI_MAP_MSGERROR:
TRACE("Not handled yet (%s)\n", MCI_MessageToString(wMsg));
dwRet = MCIERR_DRIVER_INTERNAL;
break;
case MCI_MAP_NOMEM:
TRACE("Problem mapping msg=%s from 16 to 32a\n", MCI_MessageToString(wMsg));
dwRet = MCIERR_OUT_OF_MEMORY;
break;
case MCI_MAP_OK:
case MCI_MAP_OKMEM:
dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2);
if (res == MCI_MAP_OKMEM)
MCI_UnMapMsg16To32A(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;
LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
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(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 <type>"); 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(iData, 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)
mciDriverNotify16(lpParms->dwCallback, wmd->wDeviceID, MCI_NOTIFY_SUCCESSFUL);
return 0;
errCleanUp:
if (wmd) MCI_UnLoadMciDriver(iData, wmd);
if (dwParam & MCI_NOTIFY)
mciDriverNotify16(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;
LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
TRACE("(%04x, %08lX, %p)\n", wDevID, dwParam, lpParms);
if (wDevID == MCI_ALL_DEVICE_ID) {
LPWINE_MCIDRIVER next;
EnterCriticalSection(&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 = iData->lpMciDrvs; wmd; ) {
next = wmd->lpNext;
MCI_Close(wmd->wDeviceID, dwParam, lpParms);
wmd = next;
}
LeaveCriticalSection(&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(iData, wmd);
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 = 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;
LPWINE_MCIDRIVER wmd;
LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
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:
{
DWORD cnt = 0;
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(&iData->cs);
for (wmd = iData->lpMciDrvs; wmd; wmd = wmd->lpNext) {
cnt++;
}
LeaveCriticalSection(&iData->cs);
} else {
TRACE("MCI_SYSINFO_QUANTITY: # of installed MCI drivers\n");
cnt = MCI_InstalledCount;
}
} else {
if (dwFlags & MCI_SYSINFO_OPEN) {
TRACE("MCI_SYSINFO_QUANTITY: # of open MCI drivers of type %u\n",
lpParms->wDeviceType);
EnterCriticalSection(&iData->cs);
for (wmd = iData->lpMciDrvs; wmd; wmd = wmd->lpNext) {
if (wmd->wType == lpParms->wDeviceType)
cnt++;
}
LeaveCriticalSection(&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 if (lpParms->dwNumber > MCI_InstalledCount) {
ret = MCIERR_OUTOFRANGE;
} else {
DWORD count = lpParms->dwNumber;
LPSTR ptr = MCI_lpInstallNames;
while (--count > 0) ptr += strlen(ptr) + 1;
ret = MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, ptr);
}
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)
mciDriverNotify16(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 {
switch (MCI_MapMsg16To32A(0, wMsg, &dwParam2)) {
case MCI_MAP_OK:
case MCI_MAP_OKMEM:
dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
MCI_UnMapMsg16To32A(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 {
switch (MCI_MapMsg16To32A(0, wMsg, &dwParam2)) {
case MCI_MAP_OK:
case MCI_MAP_OKMEM:
dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
MCI_UnMapMsg16To32A(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 {
switch (MCI_MapMsg16To32A(0, wMsg, &dwParam2)) {
case MCI_MAP_OK:
case MCI_MAP_OKMEM:
dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSA)dwParam2);
MCI_UnMapMsg16To32A(0, wMsg, dwParam2);
break;
default: break; /* so that gcc doesnot bark */
}
}
break;
case MCI_BREAK:
if (bFrom32) {
dwRet = MCI_Break(wDevID, dwParam1, (LPMCI_BREAK_PARMS)dwParam2);
} else {
switch (MCI_MapMsg16To32A(0, wMsg, &dwParam2)) {
case MCI_MAP_OK:
case MCI_MAP_OKMEM:
dwRet = MCI_Break(wDevID, dwParam1, (LPMCI_BREAK_PARMS)dwParam2);
MCI_UnMapMsg16To32A(0, wMsg, dwParam2);
break;
default: break; /* so that gcc does not bark */
}
}
break;
case MCI_SOUND:
/* FIXME: it seems that MCI_SOUND needs the same handling as MCI_BREAK
* but I couldn't get any doc on this MCI message
*/
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, BOOL bIs32)
{
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)(bIs32 ? (void*)dwParam2 : PTR_SEG_TO_LIN(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)(bIs32 ? (void*)dwParam2 : PTR_SEG_TO_LIN(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);
}
/**************************************************************************
* MULTIMEDIA_MciInit [internal]
*
* Initializes the MCI internal variables.
*
*/
BOOL MULTIMEDIA_MciInit(void)
{
LPSTR ptr1, ptr2;
HKEY hWineConf;
HKEY hkey;
DWORD err;
DWORD type;
DWORD count = 2048;
MCI_InstalledCount = 0;
ptr1 = MCI_lpInstallNames = HeapAlloc(GetProcessHeap(), 0, count);
if (!MCI_lpInstallNames)
return FALSE;
/* FIXME: should do also some registry diving here ? */
if (!(err = RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", &hWineConf)) &&
!(err = RegOpenKeyA(hWineConf, "options", &hkey))) {
err = RegQueryValueExA(hkey, "mci", 0, &type, MCI_lpInstallNames, &count);
RegCloseKey(hkey);
}
if (!err) {
TRACE("Wine => '%s' \n", ptr1);
while ((ptr2 = strchr(ptr1, ':')) != 0) {
*ptr2++ = 0;
TRACE("---> '%s' \n", ptr1);
MCI_InstalledCount++;
ptr1 = ptr2;
}
MCI_InstalledCount++;
TRACE("---> '%s' \n", ptr1);
ptr1 += strlen(ptr1) + 1;
} else {
GetPrivateProfileStringA("mci", NULL, "", MCI_lpInstallNames, count, "SYSTEM.INI");
while (strlen(ptr1) > 0) {
TRACE("---> '%s' \n", ptr1);
ptr1 += strlen(ptr1) + 1;
MCI_InstalledCount++;
}
}
RegCloseKey(hWineConf);
return TRUE;
}