mcicda.c

来自「Wine-20031016」· C语言 代码 · 共 1,057 行 · 第 1/3 页

C
1,057
字号
/* -*- tab-width: 8; c-basic-offset: 4 -*- *//* * MCI driver for audio CD (MCICDA) * * Copyright 1994    Martin Ayotte * Copyright 1998-99 Eric Pouech * Copyright 2000    Andreas Mohr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include "config.h"#include <stdarg.h>#include <stdio.h>#include <string.h>#include "windef.h"#include "winbase.h"#include "wingdi.h"#include "winuser.h"#include "ntstatus.h"#include "wownt32.h"#include "mmddk.h"#include "winioctl.h"#include "ntddstor.h"#include "ntddcdrm.h"#include "wine/debug.h"WINE_DEFAULT_DEBUG_CHANNEL(mcicda);#define CDFRAMES_PERSEC                 75#define CDFRAMES_PERMIN                 (CDFRAMES_PERSEC * 60)#define FRAME_OF_ADDR(a) ((a)[1] * CDFRAMES_PERMIN + (a)[2] * CDFRAMES_PERSEC + (a)[3])#define FRAME_OF_TOC(toc, idx)  FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)typedef struct {    UINT		wDevID;    int     		nUseCount;          /* Incremented for each shared open */    BOOL  		fShareable;         /* TRUE if first open was shareable */    WORD    		wNotifyDeviceID;    /* MCI device ID with a pending notification */    HANDLE 		hCallback;          /* Callback handle for pending notification */    DWORD		dwTimeFormat;    HANDLE              handle;} WINE_MCICDAUDIO;/*-----------------------------------------------------------------------*//************************************************************************** * 				MCICDA_drvOpen			[internal] */static	DWORD	MCICDA_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp){    WINE_MCICDAUDIO*	wmcda;    if (!modp) return 0xFFFFFFFF;    wmcda = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,  sizeof(WINE_MCICDAUDIO));    if (!wmcda)	return 0;    wmcda->wDevID = modp->wDeviceID;    mciSetDriverData(wmcda->wDevID, (DWORD)wmcda);    modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;    modp->wType = MCI_DEVTYPE_CD_AUDIO;    return modp->wDeviceID;}/************************************************************************** * 				MCICDA_drvClose			[internal] */static	DWORD	MCICDA_drvClose(DWORD dwDevID){    WINE_MCICDAUDIO*  wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(dwDevID);    if (wmcda) {	HeapFree(GetProcessHeap(), 0, wmcda);	mciSetDriverData(dwDevID, 0);    }    return (dwDevID == 0xFFFFFFFF) ? 1 : 0;}/************************************************************************** * 				MCICDA_GetOpenDrv		[internal] */static WINE_MCICDAUDIO*  MCICDA_GetOpenDrv(UINT wDevID){    WINE_MCICDAUDIO*	wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);    if (wmcda == NULL || wmcda->nUseCount == 0) {	WARN("Invalid wDevID=%u\n", wDevID);	return 0;    }    return wmcda;}/************************************************************************** * 				MCICDA_GetStatus		[internal] */static	DWORD    MCICDA_GetStatus(WINE_MCICDAUDIO* wmcda){    CDROM_SUB_Q_DATA_FORMAT     fmt;    SUB_Q_CHANNEL_DATA          data;    DWORD                       br;    DWORD                       mode = MCI_MODE_NOT_READY;    fmt.Format = IOCTL_CDROM_CURRENT_POSITION;    if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt),                         &data, sizeof(data), &br, NULL)) {        if (GetLastError() == STATUS_NO_MEDIA_IN_DEVICE) mode = MCI_MODE_OPEN;    } else {        switch (data.CurrentPosition.Header.AudioStatus)        {        case AUDIO_STATUS_IN_PROGRESS:          mode = MCI_MODE_PLAY;   break;        case AUDIO_STATUS_PAUSED:               mode = MCI_MODE_PAUSE;  break;        case AUDIO_STATUS_NO_STATUS:        case AUDIO_STATUS_PLAY_COMPLETE:        mode = MCI_MODE_STOP;   break;        case AUDIO_STATUS_PLAY_ERROR:        case AUDIO_STATUS_NOT_SUPPORTED:        default:            break;        }    }    return mode;}/************************************************************************** * 				MCICDA_GetError			[internal] */static	int	MCICDA_GetError(WINE_MCICDAUDIO* wmcda){    switch (GetLastError())    {    case STATUS_NO_MEDIA_IN_DEVICE:     return MCIERR_DEVICE_NOT_READY;    case STATUS_IO_DEVICE_ERROR:        return MCIERR_HARDWARE;    default:	FIXME("Unknown mode %lx\n", GetLastError());    }    return MCIERR_DRIVER_INTERNAL;}/************************************************************************** * 			MCICDA_CalcFrame			[internal] */static DWORD MCICDA_CalcFrame(WINE_MCICDAUDIO* wmcda, DWORD dwTime){    DWORD	dwFrame = 0;    UINT	wTrack;    CDROM_TOC   toc;    DWORD       br;    BYTE*       addr;    TRACE("(%p, %08lX, %lu);\n", wmcda, wmcda->dwTimeFormat, dwTime);    switch (wmcda->dwTimeFormat) {    case MCI_FORMAT_MILLISECONDS:	dwFrame = ((dwTime - 1) * CDFRAMES_PERSEC + 500) / 1000;	TRACE("MILLISECONDS %lu\n", dwFrame);	break;    case MCI_FORMAT_MSF:	TRACE("MSF %02u:%02u:%02u\n",	      MCI_MSF_MINUTE(dwTime), MCI_MSF_SECOND(dwTime), MCI_MSF_FRAME(dwTime));	dwFrame += CDFRAMES_PERMIN * MCI_MSF_MINUTE(dwTime);	dwFrame += CDFRAMES_PERSEC * MCI_MSF_SECOND(dwTime);	dwFrame += MCI_MSF_FRAME(dwTime);	break;    case MCI_FORMAT_TMSF:    default: /* unknown format ! force TMSF ! ... */	wTrack = MCI_TMSF_TRACK(dwTime);        if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,                             &toc, sizeof(toc), &br, NULL))            return 0;        if (wTrack < toc.FirstTrack || wTrack > toc.LastTrack)            return 0;        TRACE("MSF %02u-%02u:%02u:%02u\n",              MCI_TMSF_TRACK(dwTime), MCI_TMSF_MINUTE(dwTime),              MCI_TMSF_SECOND(dwTime), MCI_TMSF_FRAME(dwTime));        addr = toc.TrackData[wTrack - toc.FirstTrack].Address;        TRACE("TMSF trackpos[%u]=%d:%d:%d\n",              wTrack, addr[1], addr[2], addr[3]);        dwFrame = CDFRAMES_PERMIN * (addr[1] + MCI_TMSF_MINUTE(dwTime)) +            CDFRAMES_PERSEC * (addr[2] + MCI_TMSF_SECOND(dwTime)) +            addr[3] + MCI_TMSF_FRAME(dwTime);	break;    }    return dwFrame;}/************************************************************************** * 			MCICDA_CalcTime				[internal] */static DWORD MCICDA_CalcTime(WINE_MCICDAUDIO* wmcda, DWORD tf, DWORD dwFrame, LPDWORD lpRet){    DWORD	dwTime = 0;    UINT	wTrack;    UINT	wMinutes;    UINT	wSeconds;    UINT	wFrames;    CDROM_TOC   toc;    DWORD       br;    TRACE("(%p, %08lX, %lu);\n", wmcda, tf, dwFrame);    switch (tf) {    case MCI_FORMAT_MILLISECONDS:	dwTime = (dwFrame * 1000) / CDFRAMES_PERSEC + 1;	TRACE("MILLISECONDS %lu\n", dwTime);	*lpRet = 0;	break;    case MCI_FORMAT_MSF:	wMinutes = dwFrame / CDFRAMES_PERMIN;	wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;	wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;	dwTime = MCI_MAKE_MSF(wMinutes, wSeconds, wFrames);	TRACE("MSF %02u:%02u:%02u -> dwTime=%lu\n",	      wMinutes, wSeconds, wFrames, dwTime);	*lpRet = MCI_COLONIZED3_RETURN;	break;    case MCI_FORMAT_TMSF:    default:	/* unknown format ! force TMSF ! ... */        if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,                             &toc, sizeof(toc), &br, NULL))            return 0;	if (dwFrame < FRAME_OF_TOC(toc, toc.FirstTrack) ||            dwFrame > FRAME_OF_TOC(toc, toc.LastTrack + 1)) {	    ERR("Out of range value %lu [%u,%u]\n",		dwFrame, FRAME_OF_TOC(toc, toc.FirstTrack),                FRAME_OF_TOC(toc, toc.LastTrack + 1));	    *lpRet = 0;	    return 0;	}	for (wTrack = toc.FirstTrack; wTrack <= toc.LastTrack; wTrack++) {	    if (FRAME_OF_TOC(toc, wTrack) > dwFrame)		break;	}        wTrack--;	dwFrame -= FRAME_OF_TOC(toc, wTrack);	wMinutes = dwFrame / CDFRAMES_PERMIN;	wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;	wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;	dwTime = MCI_MAKE_TMSF(wTrack, wMinutes, wSeconds, wFrames);	TRACE("%02u-%02u:%02u:%02u\n", wTrack, wMinutes, wSeconds, wFrames);	*lpRet = MCI_COLONIZED4_RETURN;	break;    }    return dwTime;}static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms);static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);/************************************************************************** * 				MCICDA_Open			[internal] */static DWORD MCICDA_Open(UINT wDevID, DWORD dwFlags, LPMCI_OPEN_PARMSA lpOpenParms){    DWORD		dwDeviceID;    DWORD               ret = MCIERR_HARDWARE;    WINE_MCICDAUDIO* 	wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);    char                root[7];    int                 count;    char                drive = 0;    TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpOpenParms);    if (lpOpenParms == NULL) 		return MCIERR_NULL_PARAMETER_BLOCK;    if (wmcda == NULL)			return MCIERR_INVALID_DEVICE_ID;    dwDeviceID = lpOpenParms->wDeviceID;    if (wmcda->nUseCount > 0) {	/* The driver is already open on this channel */	/* If the driver was opened shareable before and this open specifies */	/* shareable then increment the use count */	if (wmcda->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))	    ++wmcda->nUseCount;	else	    return MCIERR_MUST_USE_SHAREABLE;    } else {	wmcda->nUseCount = 1;	wmcda->fShareable = dwFlags & MCI_OPEN_SHAREABLE;    }    if (dwFlags & MCI_OPEN_ELEMENT) {        if (dwFlags & MCI_OPEN_ELEMENT_ID) {            WARN("MCI_OPEN_ELEMENT_ID %8lx ! Abort\n", (DWORD)lpOpenParms->lpstrElementName);            return MCIERR_NO_ELEMENT_ALLOWED;        }        if (!isalpha(lpOpenParms->lpstrElementName[0]) || lpOpenParms->lpstrElementName[1] != ':' ||            lpOpenParms->lpstrElementName[2])        {            WARN("MCI_OPEN_ELEMENT unsupported format: %s\n", lpOpenParms->lpstrElementName);            ret = MCIERR_NO_ELEMENT_ALLOWED;            goto the_error;        }        drive = toupper(lpOpenParms->lpstrElementName[0]);        strcpy(root, "A:\\");        root[0] = drive;        if (GetDriveTypeA(root) != DRIVE_CDROM)        {            ret = MCIERR_INVALID_DEVICE_NAME;            goto the_error;        }    }    else    {        /* drive letter isn't passed... get the dwDeviceID'th cdrom in the system */        strcpy(root, "A:\\");        for (count = 0; root[0] <= 'Z'; root[0]++)        {            if (GetDriveTypeA(root) == DRIVE_CDROM && ++count >= dwDeviceID)            {                drive = root[0];                break;            }        }        if (!drive)        {            ret = MCIERR_INVALID_DEVICE_ID;            goto the_error;        }    }    wmcda->wNotifyDeviceID = dwDeviceID;    wmcda->dwTimeFormat = MCI_FORMAT_MSF;    /* now, open the handle */    strcpy(root, "\\\\.\\A:");    root[4] = drive;    wmcda->handle = CreateFileA(root, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);    if (wmcda->handle != INVALID_HANDLE_VALUE)        return 0; the_error:    --wmcda->nUseCount;    return ret;}/************************************************************************** * 				MCICDA_Close			[internal] */static DWORD MCICDA_Close(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?