首先对MCI(Media Control Interface)媒体控制接口作简单介绍,MCI是微软公司提供的一组多媒体设备和文件的标准接口,其优点是可以方便地控制绝大所数多媒体设备,包括音频、视频、影碟、录像等多媒体设备,而不需要知道它们的内部工作状况。接口所支持的媒体格式包括avi、wav、mpeg、Mp3、wma等。这里要做的就是通过公开的访问接口直接调用系统内置引擎实现MP3的播放。
接口函数的声明如下:
MCIERROR WINAPI mciSendCommand(MCIDEVICEID mciId,
UINT uMsg,
DWORD dwParam1,
DWORD dwParam2)
其中mciId指定了设备标识,这个标识会在程序员打开MCI设备时由系统提供。uMsg指定将如何控制设备,即MCI指令,最后两个参数一般是一个数据结构,标识程序在访问MCI时要的信息。MCI常用指令有MCI_OPEN、MCI_PAUSE、MCI_CLOSE、MCI_STOP、MCI_PLAY、MCI_STATUS等。
制作流程如下:
1.在对话框上分别添加一个滑动条和四个按钮,如图所示:
播放进度、播放、暂停、停止、打开文件的ID号分别设置为IDC_PROCESS、IDC_PLAY_BUTTON、IDC_PAUSE_BUTTON、IDC_STOP_BUTTON、IDC_OPEN_BUTTON。
2.新建一个CMyPlayerControl类,其头文件和实现如下:
CMyPlayerControl.h:
#pragma once
#ifndef _MY_PLAYER_CONTROL_H_
#define _MY_PLAYER_CONTROL_H_
//插入多媒体头文件
#include
class CMyPlayerControl
{
public:
CMyPlayerControl(void);
~CMyPlayerControl(void);
public:
BOOL Open(LPCWSTR lpFileName);//打开文件
void Play();//播放
void Close();//关闭
void Stop();//停止
void Pause();//暂停
DWORD GetLength(DWORD dwItem);//获取歌曲长度
void SetWindowHwnd(HWND hWnd);//设置主窗口句柄
private:
MCI_OPEN_PARMS mciOpen;//打开设备参数
HWND m_hWnd;//主窗口句柄
DWORD dwFrom;//播放起始点
};
#endif
CMyPlayerControl.cpp:因为类中调用了系统的MCI接口的API函数,所以必须加入winmm.lib这个静态链接库文件。
#include "StdAfx.h"
#include "MyPlayerControl.h"
CMyPlayerControl::CMyPlayerControl(void)
{
}
CMyPlayerControl::~CMyPlayerControl(void)
{
Close();
}
DWORD CMyPlayerControl::GetLength(DWORD dwItem)
{
//得到当前文件状态
MCI_STATUS_PARMS mcistatusparms;
mcistatusparms.dwCallback=(DWORD)m_hWnd;
mcistatusparms.dwItem=dwItem;
mcistatusparms.dwReturn=0;
mciSendCommand(mciOpen.wDeviceID,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)&mcistatusparms);
return mcistatusparms.dwReturn;
}
BOOL CMyPlayerControl::Open(LPCWSTR lpFileName)
{
//如果有打开的MCI设备就关闭
if(mciOpen.wDeviceID)Close();
//初始化MCI_OPEN_PARMS结构中的文件类型
mciOpen.lpstrDeviceType=NULL;
//播放文件路径
mciOpen.lpstrElementName=lpFileName;
//向MCI设备发送命令消息(在打开设备时,设备号为0)
if(mciSendCommand(0,MCI_OPEN,MCI_DEVTYPE_WAVEFORM_AUDIO,(DWORD)&mciOpen))
{
return FALSE;
}
dwFrom=MCI_MAKE_HMS(0,0,0);
return TRUE;
}
void CMyPlayerControl::Play()
{
//播放参数结构
MCI_PLAY_PARMS mciplayparms;
//得到文件大小
DWORD cdlen=GetLength(MCI_STATUS_LENGTH);
DWORD cdto=MCI_MAKE_HMS(MCI_HMS_HOUR(cdlen),MCI_HMS_MINUTE(cdlen),MCI_HMS_SECOND(cdlen));//把文件中读出的大小转换为时间数量
mciplayparms.dwCallback=NULL;
mciplayparms.dwFrom=dwFrom;//设置起始位置
mciplayparms.dwTo=cdto;//设置终止位置
if(mciOpen.wDeviceID!=0)//判断是否打开文件
{//播放音乐
mciSendCommand(mciOpen.wDeviceID,MCI_PLAY,MCI_TO|MCI_FROM,(DWORD)(LPVOID)&mciplayparms);
}
}
void CMyPlayerControl::Close()
{
if(mciOpen.wDeviceID)
{
//执行MCI_CLOSE操作,关闭MCI设备
mciSendCommand(mciOpen.wDeviceID,MCI_CLOSE,NULL,NULL);
}
}
void CMyPlayerControl::Stop()
{
if(mciOpen.wDeviceID)
{//执行MCI_STOP操作,停止播放音乐
mciSendCommand(mciOpen.wDeviceID,MCI_STOP,NULL,NULL);
//把播放位置设定为音乐文件的开头(下一次播放操作从文件开头位置开始)
mciSendCommand(mciOpen.wDeviceID,MCI_SEEK,MCI_SEEK_TO_START,NULL);
}
dwFrom=MCI_MAKE_HMS(0,0,0);
}
void CMyPlayerControl::Pause()
{
if(mciOpen.wDeviceID)
{//执行MCI_PAUSE操作,暂停播放音乐
DWORD dwsf=GetLength(MCI_STATUS_POSITION);
dwFrom=MCI_MAKE_MSF(MCI_MSF_MINUTE(dwsf),MCI_MSF_SECOND(dwsf),MCI_MSF_FRAME(dwsf));
//执行MCI_PAUSE操作,暂停播放音乐
mciSendCommand(mciOpen.wDeviceID,MCI_PAUSE,NULL,NULL);
}
}
void CMyPlayerControl::SetWindowHwnd(HWND hWnd)
{
m_hWnd=hWnd;
}
使用类的定义方法,可以使这个类具有更高的重用性。
CMp3PlayerDlg.h的声明中为各个按钮添加单击事件响应函数,并添加OnOk、OnCancel虚函数,并对WM_TIMER添加响应函数,对滑动条添加私有变量CSliderControl m_process以及。其具体代码如下:
// Mp3PlayerDlg.h : 头文件
//
#if !defined(AFX_MP3PLAYERDLG_H__)
#define AFX_MP3PLAYERDLG_H__
#if _MSG_VER > 1000
#pragma once
#endif
#include"MyPlayerControl.h"
#include "afxcmn.h"
// CMp3PlayerDlg 对话框
class CMp3PlayerDlg : public CDialogEx
{
// 构造
public:
CMp3PlayerDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
enum { IDD = IDD_MP3PLAYER_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedPlayButton();
afx_msg void OnBnClickedPauseButton();
afx_msg void OnBnClickedStopButton();
afx_msg void OnBnClickedOpenButton();
CSliderCtrl m_process;
private:
CMyPlayerControl m_myPlayerControl;
CString m_strFileName;
virtual void OnCancel();
virtual void OnOK();
public:
afx_msg void OnTimer(UINT_PTR nIDEvent);
};
#endif
在声明过函数之后,在源文件CMp3PlayerDlg.cpp中进行具体实现:
// Mp3PlayerDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "Mp3Player.h"
#include "Mp3PlayerDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CMp3PlayerDlg 对话框
CMp3PlayerDlg::CMp3PlayerDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CMp3PlayerDlg::IDD, pParent)
, m_strFileName(_T(""))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CMp3PlayerDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_PROCESS, m_process);
}
BEGIN_MESSAGE_MAP(CMp3PlayerDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_PLAY_BUTTON, &CMp3PlayerDlg::OnBnClickedPlayButton)
ON_BN_CLICKED(IDC_PAUSE_BUTTON, &CMp3PlayerDlg::OnBnClickedPauseButton)
ON_BN_CLICKED(IDC_STOP_BUTTON, &CMp3PlayerDlg::OnBnClickedStopButton)
ON_BN_CLICKED(IDC_OPEN_BUTTON, &CMp3PlayerDlg::OnBnClickedOpenButton)
ON_WM_TIMER()
END_MESSAGE_MAP()
// CMp3PlayerDlg 消息处理程序
BOOL CMp3PlayerDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CMp3PlayerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CMp3PlayerDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMp3PlayerDlg::OnQueryDragIcon()
{
return static_cast(m_hIcon);
}
void CMp3PlayerDlg::OnBnClickedPlayButton()
{
// TODO: 在此添加控件通知处理程序代码
DWORD cdlen=m_myPlayerControl.GetLength(MCI_STATUS_LENGTH);
m_myPlayerControl.Play();
m_process.SetRange(0,cdlen);
SetTimer(0,1000,NULL);
}
void CMp3PlayerDlg::OnBnClickedPauseButton()
{
// TODO: 在此添加控件通知处理程序代码
m_myPlayerControl.Pause();//调用暂停
}
void CMp3PlayerDlg::OnBnClickedStopButton()
{
// TODO: 在此添加控件通知处理程序代码
m_myPlayerControl.Stop();
m_process.SetPos(0);
KillTimer(0);
}
void CMp3PlayerDlg::OnBnClickedOpenButton()
{
// TODO: 在此添加控件通知处理程序代码
CString strFilter(_T("MP3 Files(*.mp3)|*.mp3||"));
CFileDialog OpenDlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,strFilter);
int nFlags=OpenDlg.DoModal();//通过打开对话框选择MP3文件
if(nFlags==IDOK)
{//用户单击的是“打开”按钮,将文件路径名赋给成员变量m_strFileName备用
m_strFileName=OpenDlg.GetPathName();
//打开MCI设备,并将设备分配给选中的文件使用
m_myPlayerControl.Open(m_strFileName);
}
}
void CMp3PlayerDlg::OnCancel()
{
// TODO: 在此添加专用代码和/或调用基类
CDialogEx::OnCancel();
}
void CMp3PlayerDlg::OnOK()
{
// TODO: 在此添加专用代码和/或调用基类
CDialogEx::OnOK();
}
void CMp3PlayerDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//每秒钟得到的当前播放进度
DWORD cdf=m_myPlayerControl.GetLength(MCI_STATUS_POSITION);
m_process.SetPos(cdf);//设置进度条位置
CDialogEx::OnTimer(nIDEvent);//调用其他Timer
}
测试程序效果。操作方法为:单击“打开文件”按钮,弹出“打开”对话框。指定文件,并单击对话框中的“打开”按钮,打开指定文件后,单击“播放”按钮,这时进度条会自动向右增加,并且可以听到音乐开始播放了。这个例子只支持MP3格式的音乐。
至此,完成。