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 + -
显示快捷键?