用VC做一个无需控件支持的MP3播放器



交大蓝盾论坛 -> 开发研究 -> 用VC做一个无需控件支持的MP3播放器 登录 -> 注册 -> 回复主题 -> 发表主题

 

 

zhouyuhi2005-10-28 22:02
[被屏蔽广告]

首先,让我们先来了解一下MCI(Media Control Interface)媒体控制接口。MCI是MircroSoft提供的一组多媒体设备和文件的标准接口,它的好处是可以方便地控制绝大多数多媒体设备包括音频、视频、影碟、录像等多媒体设备,而不需要知道它们的内部工作状况。它所支持的媒体格式包括avi、wav、mpeg、cda等等。由于Windows内置了MP3播放引擎MCI也支持MP3,但由于某种不为我们所知的原因,Microsoft并没有公开MCI的这个访问功能。我们所要做的就是利用这一非公开的访问接口直接调用系统内置引擎实现MP3的播放。在windows的系统配置文件system.ini(C:/windows/)中有一个[MCI]配置项,该项下列出了通过MCI接口所接受的MCI设备类型与所调用引擎的对应关系,如:
mci]
cdaudio=mcicda.drv
sequencer=mciseq.drv
waveaudio=mciwave.drv
avivideo=mciavi.drv
我们只需添加条目:mp3audio=mciqtz.drv
其中mciqtz.drv即MP3播放引擎驱动。我们在通过MCI接口编程时只要显式地指明所使用的设备类型为mp3audio,即可实现播放MP3的目的。余下的工作就只是通过调用MCI接口函数实现播放器的功能了。让我们再来了解一下MCI接口函数。

一般说来,程序员使用两个函数就可以与MCI打交道了,这两个函数的声明都在mmsystem.h中:
1.MCIERROR mciSendString(LPCTSTR lpszCommand,LPTSTR lpszReturnString,UINT cchReturn,HANDLE hwndCallback);命令字符串方式,用接近于日常生活用语的方式发送控制命令,适用于RAD编程如VB。
2. MCIERROR mciSendCommand(MCIDEVICEID
wDeviceID:指定了设备标识,这个标识会在程序员打开MCI设备时由系统提供。
UINTuMsg:指定将如何控制设备,即"MCI指令",比较常用的指令有MCI_OPEN、MCI_CLOSE、MCI_PLAY、MCI_STOP、MCI_PAUSE、MCI_STATUS等等。
DWORD dwFlags:为访问标识。
DWORD dwParam):一般是一个数据结构,标识程序在访问MCI时要的一些信息。我们在实例中将通过使用数据结构MIC_OPEN_PARMS来指定设备类型的。
命令消息方式,用专业语法发送控制消息,适用于VC等语言编程,此方式直接与MCI设备打交道,我们的实例即使用此函数。
MIC_OPEN_PARMS结构如下:
typedef struct { DWORD dwCallback;
MCIDEVICEID wDeviceID; //设备ID
LPCSTR lpstrDeviceType; //设备类型名
LPCSTR lpstrElementName; //设备元素名(通常是要处理的文件名)
LPCSTR lpstrAlias;
MCI_OPEN_PARMS;

2.制作过程
下面我们就以一个实例来说明MP3播放器的具体实现方法:
1.建立一个MFC AppWizard(exe)应用工程mp3Player。
在MFC AppWizard向导的第一步中选择Single Document,在第六步将CMp3PlayerView的base Class设为CformView,再点击按键Finish->OK完成工程的建立。
2.在资源编辑器中编辑ID号为IDD_MP3PLAYER_FORM的Dialog,在其上添加两个Static Text 控件,其一命名为STATIC1,用来显示状态提示信息。如图1:

(图片统一在后面,需5点威望)

绘制工具条如图2:
(图片统一在后面,需5点威望)


设置菜单如图3:

(图片统一在后面,需5点威望)
3.通过Class Wizard创建一个新类CMciControl,代码如下:
// MciControl.h: interface for the CMciControl class.
// Copyright(c) 2003 by lilipuss
//

#if !defined(AFX_MCICONTROL_H__D4CDBB30_01C4_11D8_BEEE_C2001FA02C0E__INCLUDED_)
#define AFX_MCICONTROL_H__D4CDBB30_01C4_11D8_BEEE_C2001FA02C0E__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "mmsystem.h"
class CMciControl
{
private:
    MCI_OPEN_PARMS mciOpen;
public:
    CMciControl();
    ~CMciControl() {Close(); }

    //通过描述字符串打开设备
    MCIERROR Open(LPCSTR DeviceType,LPCSTR filename);
    void Play(void);   //播放MCI
    void Close(void);     //关闭设备
    void Stop(void);     //停止设备
    void Pause(void);   //暂停设备
};

#endif // !defined(AFX_MCICONTROL_H__D4CDBB30_01C4_11D8_BEEE_C2001FA02C0E__INCLUDED_)

// MciControl.cpp: implementation of the CMciControl class.
// Copyright(c) 2003 by lilipuss
//

#include "stdafx.h"
#include "mp3player.h"
#include "MciControl.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//
// Construction/Destruction
//

CMciControl::CMciControl()
{
}
MCIERROR CMciControl::Open(LPCSTR DeviceType,LPCSTR filename)
{
    //如果有打开的MCI设备就关闭
    if (mciOpen.wDeviceID) Close();
    //初始化MCI_OPEN_PARMS结构
    mciOpen.lpstrDeviceType=DeviceType;
    mciOpen.lpstrElementName=filename;
    //除了打开设备设备代码为0,
    //下面的任何mciSendCommand语句都要指定设备代码。
    if ( mciSendCommand(NULL,
                    MCI_OPEN,
                    MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
                  (DWORD)&mciOpen))
        return FALSE;
    return TRUE;
}
void CMciControl::Play(void)
{
    //执行MCI_PLAY操作,播放音乐
    mciSendCommand(mciOpen.wDeviceID,MCI_PLAY,NULL,NULL);
}
void CMciControl::Close(void)
{
    if (mciOpen.wDeviceID)
        //执行MCI_CLOSE操作,关闭MCI设备
        mciSendCommand(mciOpen.wDeviceID,MCI_CLOSE,NULL,NULL);

}
void CMciControl::Stop(void)
{
    if (mciOpen.wDeviceID)
        //执行MCI_STOP操作,停止播放音乐
        mciSendCommand(mciOpen.wDeviceID,MCI_STOP,NULL,NULL);
        //把播放位置设定为音乐文件的开头(使下一次播放操作从文件开头位置开始)
        mciSendCommand(mciOpen.wDeviceID,MCI_SEEK,MCI_SEEK_TO_START,NULL);
}
void CMciControl::Pause(void)
{
    if (mciOpen.wDeviceID)
        //执行MCI_PAUSE操作,暂停播放音乐
        mciSendCommand(mciOpen.wDeviceID,MCI_PAUSE,NULL,NULL);
}

4.在CMp3PlayerView类定义中添加三个私有成员变量:

private:
    //MCI状态变量 default=0x1111
        //播放状态:0x0001
        //暂停状态:0x0010
        //停止状态:0x0100
    LONG m_lStatus;
    //音乐文件名 default=_T("")
    CString m_strFileName;
    //CMciControl Object,用来控制MCI设备的操作
    CMciControl m_MciCtrl;

5.在CMp3PlayerView.cpp头部加入
//API函数WritePrivateProfileString声明在windows.h中
#include "windows.h"
在CMp3PlayerView的成员函数OnInitialUpdate()中添加如下代码:
//调用API函数在system.ini的[mci]项中添加mp3audio=mciqtz.drv
    WritePrivateProfileString("MCI",
                            "mp3audio",
                            "mciqtz.drv",
                            "C://windows//system.ini");
    //初始化状态提示
    CString str("目前无音乐文件被选中/n[请通过菜单进行选择]");
    SetDlgItemText(IDC_STATIC1,str);

6.通过Class Wizard为CMp3PlayerView类添加下列函数:
void OnFileOpen();
      void OnPlay();
      void OnPause();
      void OnStop();
      void OnUpdatePause(CCmdUI* pCmdUI);
      void OnUpdatePlay(CCmdUI* pCmdUI);
      void OnUpdateStop(CCmdUI* pCmdUI);
  函数代码及说明如下:
        void CMp3PlayerView::OnFileOpen()
{  
    //通过打开对话框选择mp3音乐文件
  CString strFilter("MP3 Files (*.mp3)|*.mp3||");
    CFileDialog OpenDlg(TRUE,
NULL,
NULL,
OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,
strFilter);
    int nFlags=OpenDlg.DoModal();
    if(nFlags==IDOK){
        //将文件路径名赋给成员变量m_strFileName备用
        m_strFileName=OpenDlg.GetPathName();
        //打开一个MCI设备,并把该设备分配给选中的文件使用
        m_MciCtrl.Open("mp3audio",m_strFileName);
        //播放选中的mp3音乐文件
        OnPlay();
    }    

}

void CMp3PlayerView::OnPlay()
{    
    //执行播放操作
    m_MciCtrl.Play();

    //设置当前状态提示
    CString str("当前状态:播放/n曲目:");
    str+=m_strFileName;
    SetDlgItemText(IDC_STATIC1,str);
    //设置状态变量
    m_lStatus=0x0001;
}

void CMp3PlayerView::OnPause()
{
    //执行暂停操作
    m_MciCtrl.Pause();

    //设置当前状态提示
    CString str("当前状态:暂停/n曲目:");
    str+=m_strFileName;
    SetDlgItemText(IDC_STATIC1,str);
    //设置状态变量
    m_lStatus=0x0010;
}

void CMp3PlayerView::OnStop()
{
    //执行停止操作
    m_MciCtrl.Stop();

    //设置当前状态提示
    CString str("当前状态:停止/n曲目:");
    str+=m_strFileName;
    SetDlgItemText(IDC_STATIC1,str);
    //设置状态变量
    m_lStatus=0x0100;
}

void CMp3PlayerView::OnUpdatePause(CCmdUI* pCmdUI)
{
    //当前状态为暂停或播放时,暂停按钮不可用
    pCmdUI->Enable(!(m_lStatus&0x0010)&&!(m_lStatus&0x0100));
   
}

void CMp3PlayerView::OnUpdatePlay(CCmdUI* pCmdUI)
{
    //当前状态为播放时,播放按钮不可用
    pCmdUI->Enable(!(m_lStatus&0x0001));
   
}

void CMp3PlayerView::OnUpdateStop(CCmdUI* pCmdUI)
{
    //当前状态为停止时,停止按钮不可用
    pCmdUI->Enable(!(m_lStatus&0x0100));
}

7.在"projoct"菜单下单击setting,弹出设置对话框,在"link"下"object/librarymodules"下加入"winmm.lib",编译并运行程序,效果图如图4:
(图片统一在后面,需5点威望)

3.结束语
上面的例子只支持mp3格式,实际上通过对MCI接口的编程我们可以实现对许多种格式的音视频文件的播放控制,无需任何专门的控件,具体的实现方法与上例类似。有兴趣的读者可以参阅MSDN,完全可以制作一个相当专业的播放器。文章中的实例在Windows98系统下以VC++6.0编译通过.

kuanghanli2005-11-03 19:28
不过,现在大多数优秀的播放器都是免费的。
学习这些技术的话,可能只有收藏起来,实际中可能不会用哦~

大家想想,我们那些方面的技术,以后可能会很有出息呢?
唉,本人正在苦恼中啊……

zhouyuhi2005-11-04 09:25
也是啊,可是我们在学习这个的时候可以学到好多东西哦,比如好多理念性的东西,虽然我们做出来后没有什么太大的意义,根本比不上那些免费的播放软件,那我们把它当成是一种对自己的能力的挑战吧,做出之后还是有一点成就感 的,呵~~~~~~

popboy2005-11-04 22:23
不过这样的播放器网上有啊,其实感觉也没有什么区别,也没必要写那么多代码。
不过作为一种练习还是不错的!!

万年穿山甲2005-11-05 01:53
为什么都要急于求成啊。基础的东西不会编,你会编什么东西?


查看完整版本: [-- 用VC做一个无需控件支持的MP3播放器 --] [-- top --]
<script language="JavaScript" type="text/javascript"> function CopyCode(obj){ var js = document.body.createTextRange(); js.moveToElementText(obj); js.select(); js.execCommand("Copy"); } </script>

Powered by PHPWind v4.3.2 Code © 2003-05 PHPWind
Time 0.017045 second(s),query:6 Gzip enabled

You can contact us

 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值