📄 mci.c
字号:
/*
* MCI internal functions
*
* Copyright 1998/1999 Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* TODO:
* - implement WINMM (32bit) multitasking and use it in all MCI drivers
* instead of the home grown one
* - 16bit mmTaskXXX functions are currently broken because the 16
* loader does not support binary command lines => provide Wine's
* own mmtask.tsk not using binary command line.
* - correctly handle the MCI_ALL_DEVICE_ID in functions.
* - finish mapping 16 <=> 32 of MCI structures and commands
* - implement auto-open feature (ie, when a string command is issued
* for a not yet opened device, MCI automatically opens it)
* - use a default registry setting to replace the [mci] section in
* configuration file (layout of info in registry should be compatible
* with all Windows' version - which use different layouts of course)
* - implement automatic open
* + only works on string interface, on regular devices (don't work on all
* nor custom devices)
* - command table handling isn't thread safe
*/
/* to be cross checked:
* - heapalloc for *sizeof(WCHAR) when needed
* - size of string in WCHAR or bytes? (#chars for MCI_INFO, #bytes for MCI_SYSINFO)
*/
#include "config.h"
#include "wine/port.h"
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winreg.h"
#include "mmsystem.h"
#include "winuser.h"
#include "winnls.h"
#include "winreg.h"
#include "wownt32.h"
#include "digitalv.h"
#include "winemm.h"
#include "wine/debug.h"
#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(mci);
WINMM_MapType (*pFnMciMapMsg16To32W) (WORD,WORD,DWORD,DWORD*) /* = NULL */;
WINMM_MapType (*pFnMciUnMapMsg16To32W)(WORD,WORD,DWORD,DWORD) /* = NULL */;
WINMM_MapType (*pFnMciMapMsg32WTo16) (WORD,WORD,DWORD,DWORD*) /* = NULL */;
WINMM_MapType (*pFnMciUnMapMsg32WTo16)(WORD,WORD,DWORD,DWORD) /* = NULL */;
/* First MCI valid device ID (0 means error) */
#define MCI_MAGIC 0x0001
/* MCI settings */
static const WCHAR wszHklmMci [] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','M','C','I',0};
static const WCHAR wszNull [] = {0};
static const WCHAR wszAll [] = {'A','L','L',0};
static const WCHAR wszMci [] = {'M','C','I',0};
static const WCHAR wszOpen [] = {'o','p','e','n',0};
static const WCHAR wszSystemIni[] = {'s','y','s','t','e','m','.','i','n','i',0};
/* dup a string and uppercase it */
inline static LPWSTR str_dup_upper( LPCWSTR str )
{
INT len = (strlenW(str) + 1) * sizeof(WCHAR);
LPWSTR p = HeapAlloc( GetProcessHeap(), 0, len );
if (p)
{
memcpy( p, str, len );
CharUpperW( p );
}
return p;
}
/**************************************************************************
* MCI_GetDriver [internal]
*/
LPWINE_MCIDRIVER MCI_GetDriver(UINT16 wDevID)
{
LPWINE_MCIDRIVER wmd = 0;
EnterCriticalSection(&WINMM_IData.cs);
for (wmd = WINMM_IData.lpMciDrvs; wmd; wmd = wmd->lpNext) {
if (wmd->wDeviceID == wDevID)
break;
}
LeaveCriticalSection(&WINMM_IData.cs);
return wmd;
}
/**************************************************************************
* MCI_GetDriverFromString [internal]
*/
UINT MCI_GetDriverFromString(LPCWSTR lpstrName)
{
LPWINE_MCIDRIVER wmd;
UINT ret = 0;
if (!lpstrName)
return 0;
if (!strcmpiW(lpstrName, wszAll))
return MCI_ALL_DEVICE_ID;
EnterCriticalSection(&WINMM_IData.cs);
for (wmd = WINMM_IData.lpMciDrvs; wmd; wmd = wmd->lpNext) {
if (wmd->lpstrElementName && strcmpW(wmd->lpstrElementName, lpstrName) == 0) {
ret = wmd->wDeviceID;
break;
}
if (wmd->lpstrDeviceType && strcmpiW(wmd->lpstrDeviceType, lpstrName) == 0) {
ret = wmd->wDeviceID;
break;
}
if (wmd->lpstrAlias && strcmpiW(wmd->lpstrAlias, lpstrName) == 0) {
ret = wmd->wDeviceID;
break;
}
}
LeaveCriticalSection(&WINMM_IData.cs);
return ret;
}
/**************************************************************************
* MCI_MessageToString [internal]
*/
const char* MCI_MessageToString(UINT wMsg)
{
static char buffer[100];
#define CASE(s) case (s): return #s
switch (wMsg) {
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);
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;
}
}
LPWSTR MCI_strdupAtoW( LPCSTR str )
{
LPWSTR ret;
INT len;
if (!str) return NULL;
len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
return ret;
}
LPSTR MCI_strdupWtoA( LPCWSTR str )
{
LPSTR ret;
INT len;
if (!str) return NULL;
len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
ret = HeapAlloc( GetProcessHeap(), 0, len );
if (ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
return ret;
}
static int MCI_MapMsgAtoW(UINT msg, DWORD_PTR dwParam1, DWORD_PTR *dwParam2)
{
if (msg < DRV_RESERVED) return 0;
switch (msg)
{
case MCI_CLOSE:
case MCI_CONFIGURE:
case MCI_PLAY:
case MCI_SEEK:
case MCI_STOP:
case MCI_PAUSE:
case MCI_GETDEVCAPS:
case MCI_SPIN:
case MCI_SET:
case MCI_STEP:
case MCI_RECORD:
case MCI_BREAK:
case MCI_SOUND:
case MCI_STATUS:
case MCI_CUE:
case MCI_REALIZE:
case MCI_PUT:
case MCI_WHERE:
case MCI_FREEZE:
case MCI_UNFREEZE:
case MCI_CUT:
case MCI_COPY:
case MCI_PASTE:
case MCI_UPDATE:
case MCI_RESUME:
case MCI_DELETE:
case MCI_MONITOR:
case MCI_SETAUDIO:
case MCI_SIGNAL:
case MCI_SETVIDEO:
case MCI_LIST:
return 0;
case MCI_OPEN:
{
MCI_OPEN_PARMSA *mci_openA = (MCI_OPEN_PARMSA*)*dwParam2;
MCI_OPEN_PARMSW *mci_openW;
DWORD_PTR *ptr;
ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD_PTR) + sizeof(*mci_openW) + 2 * sizeof(DWORD));
if (!ptr) return -1;
*ptr++ = *dwParam2; /* save the previous pointer */
*dwParam2 = (DWORD_PTR)ptr;
mci_openW = (MCI_OPEN_PARMSW *)ptr;
if (dwParam1 & MCI_NOTIFY)
mci_openW->dwCallback = mci_openA->dwCallback;
if (dwParam1 & MCI_OPEN_TYPE)
{
if (dwParam1 & MCI_OPEN_TYPE_ID)
mci_openW->lpstrDeviceType = (LPWSTR)mci_openA->lpstrDeviceType;
else
mci_openW->lpstrDeviceType = MCI_strdupAtoW(mci_openA->lpstrDeviceType);
}
if (dwParam1 & MCI_OPEN_ELEMENT)
{
if (dwParam1 & MCI_OPEN_ELEMENT_ID)
mci_openW->lpstrElementName = (LPWSTR)mci_openA->lpstrElementName;
else
mci_openW->lpstrElementName = MCI_strdupAtoW(mci_openA->lpstrElementName);
}
if (dwParam1 & MCI_OPEN_ALIAS)
mci_openW->lpstrAlias = MCI_strdupAtoW(mci_openA->lpstrAlias);
/* FIXME: this is only needed for specific types of MCI devices, and
* may cause a segfault if the two DWORD:s don't exist at the end of
* mci_openA
*/
memcpy(mci_openW + 1, mci_openA + 1, 2 * sizeof(DWORD));
}
return 1;
case MCI_WINDOW:
if (dwParam1 & MCI_ANIM_WINDOW_TEXT)
{
MCI_ANIM_WINDOW_PARMSA *mci_windowA = (MCI_ANIM_WINDOW_PARMSA *)*dwParam2;
MCI_ANIM_WINDOW_PARMSW *mci_windowW;
mci_windowW = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_windowW));
if (!mci_windowW) return -1;
*dwParam2 = (DWORD_PTR)mci_windowW;
mci_windowW->lpstrText = MCI_strdupAtoW(mci_windowA->lpstrText);
if (dwParam1 & MCI_NOTIFY)
mci_windowW->dwCallback = mci_windowA->dwCallback;
if (dwParam1 & MCI_ANIM_WINDOW_HWND)
mci_windowW->hWnd = mci_windowA->hWnd;
if (dwParam1 & MCI_ANIM_WINDOW_STATE)
mci_windowW->nCmdShow = mci_windowA->nCmdShow;
return 1;
}
return 0;
case MCI_SYSINFO:
{
MCI_SYSINFO_PARMSA *mci_sysinfoA = (MCI_SYSINFO_PARMSA *)*dwParam2;
MCI_SYSINFO_PARMSW *mci_sysinfoW;
DWORD_PTR *ptr;
ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_sysinfoW) + sizeof(DWORD_PTR));
if (!ptr) return -1;
*ptr++ = *dwParam2; /* save the previous pointer */
*dwParam2 = (DWORD_PTR)ptr;
mci_sysinfoW = (MCI_SYSINFO_PARMSW *)ptr;
if (dwParam1 & MCI_NOTIFY)
mci_sysinfoW->dwCallback = mci_sysinfoA->dwCallback;
mci_sysinfoW->dwRetSize = mci_sysinfoA->dwRetSize;
mci_sysinfoW->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mci_sysinfoW->dwRetSize);
mci_sysinfoW->dwNumber = mci_sysinfoA->dwNumber;
mci_sysinfoW->wDeviceType = mci_sysinfoA->wDeviceType;
return 1;
}
case MCI_INFO:
{
MCI_INFO_PARMSA *mci_infoA = (MCI_INFO_PARMSA *)*dwParam2;
MCI_INFO_PARMSW *mci_infoW;
DWORD_PTR *ptr;
ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_infoW) + sizeof(DWORD_PTR));
if (!ptr) return -1;
*ptr++ = *dwParam2; /* save the previous pointer */
*dwParam2 = (DWORD_PTR)ptr;
mci_infoW = (MCI_INFO_PARMSW *)ptr;
if (dwParam1 & MCI_NOTIFY)
mci_infoW->dwCallback = mci_infoA->dwCallback;
mci_infoW->dwRetSize = mci_infoA->dwRetSize * sizeof(WCHAR); /* it's not the same as SYSINFO !!! */
mci_infoW->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mci_infoW->dwRetSize);
return 1;
}
case MCI_SAVE:
{
MCI_SAVE_PARMSA *mci_saveA = (MCI_SAVE_PARMSA *)*dwParam2;
MCI_SAVE_PARMSW *mci_saveW;
mci_saveW = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_saveW));
if (!mci_saveW) return -1;
*dwParam2 = (DWORD_PTR)mci_saveW;
if (dwParam1 & MCI_NOTIFY)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -