MCI详解

来源:互联网 发布:婚姻知乎 编辑:程序博客网 时间:2024/05/17 06:40
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
打开设备 
    MCI为不同的多媒体设备打开提供相应的数据结构类型。
    若不想使用设备中特定的参数数据,则可使用统一的MCI_OPEN_PARMS结构,原型:
    typedef struct 
    {   DWORD   dwCallback;         
// 低字节用于MCI_NOTIFY的窗口句柄
        MCIDEVICEID  wDeviceID;     // 返回的设备标识符
        LPCSTR       lpstrDeviceType;   // MCI设备的类型
        LPCSTR       lpstrElementName;  // 设备元素
        LPCSTR       lpstrAlias;        // 可选的设备别名
    } MCI_OPEN_PARMS;

打开多媒体设备的过程:定义一个MCI_OPEN_PARMS结构类型变量,给结构变量中的相应参数赋值,
调用mciSendCommand向设备发送MCI_OPEN命令消息,成功调用时,可获得相应的设备标识符。
例如,下面的代码是打开波形音频设备:
    WORD  wDeviceID;        
// MCI设备ID
    CString  fileName;      // 波形文件名
    ...
    MCI_OPEN_PARMS  openParms;  
// MCI设备打开参数
    openParms.lpstrDeviceType = "waveaudio";    // 波形音频设备
    openParms.lpstrElementName = fileName;
    
if (mciSendCommand (NULL, MCI_OPEN, 
    MCI_OPEN_ELEMENT | MCI_OPEN_TYPE, 
    (DWORD)(LPVOID) &openParms))    
return FALSE;
    wDeviceID = openParms.wDeviceID;

设置或获取设备信息
使用MCI_SET和MCI_STATUS命令可以用来设置和获取设备信息,
在用函数mciSendCommand发送命令时,使用相应的MCI_SET_PARMS和MCI_STATUS_PARMS结构
原型:
    
typedef struct 
    {   DWORD   dwCallback; 
// 低字节用于MCI_NOTIFY的窗口句柄
        DWORD   dwTimeFormat;       // 时间格式
        DWORD   dwAudio;            // 输出声道
    } MCI_SET_PARMS;
    
typedef struct 
    {   DWORD   dwCallback;     
// 低字节用于MCI_NOTIFY的窗口句柄
        DWORD   dwReturn;           // 要获取的设备信息
        DWORD   dwItem;             // 需要获取的信息项
        DWORD   dwTrack;            // 曲目的长度或曲目号
    } MCI_STATUS_PARMS; 
例如,下面的代码是将波形音频设备的时间格式设成毫秒:
    MCI_SET_PARMS setParms;
    setParms.dwTimeFormat=MCI_FORMAT_MILLISECONDS;
    
if (mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT,
    (DWORD)(LPVOID) &setParms))
    
return FALSE;
播放设备
使用MCI_PLAY命令可以使设备播放多媒体文件,并在用函数mciSendCommand发送命令时,使用相应的MCI_PLAY_PARMS结构,其原型如下:
    
typedef struct 
    {   DWORD dwCallback;       
// 低字节用于MCI_NOTIFY的窗口句柄
        DWORD   dwFrom;             // 播放的起点位置
        DWORD   dwTo;           // 播放的终点位置
    } MCI_PLAY_PARMS;
例如,下面的代码是播放波形音频设备:
    MCI_PLAY_PARMS playParms;
    
// 定位到开始位置
    mciSendCommand (wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, NULL);
    
// 播放设备
    if (mciSendCommand (wDeviceID, MCI_PLAY, NULL
        (DWORD)(LPVOID) &playParms))
        
return FALSE;
    
else
        
return TRUE; 
    
例如,若接收MM_MCINOTIFY消息的窗口是一个对话框CMyDlg,则添加消息处理的过程如下:
    (
1)切换到项目工作区窗口的ClassView页面,右击CMyDlg类,选择快捷菜单中的“Add Member Function...”命令。为CMyDlg类添加保护型的成员函数,原型:
    
protected:
        LRESULT OnMCINotify(WPARAM wParam,LPARAM lParam);
    (
2)在类CMyDlg的消息入口处,添加下列消息宏指令:
    BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
        
//{{AFX_MSG_MAP(CMyDlg)
        ...
        
//}}AFX_MSG_MAP
        ON_MESSAGE(MM_MCINOTIFY,OnMCINotify)
    END_MESSAGE_MAP()
    (
3)编写CMyDlg::OnMCINotify函数代码:
    LRESULT CMyDlg::OnMCINotify(WPARAM wParam, LPARAM lParam)
    {   ...
        
return FALSE;
    }
    (
4)关闭设备
    使用MCI_STOP和MCI_CLOSE命令可以分别用来停止播放和关闭设备。不需要设置或返回附加的信息,因此不必考虑相应的MCI_GENERIC_PARMS结构。 

10.3使用MCIWnd窗口类 
          MCIWnd是一个控制多媒体设备的窗口类。若在应用程序中使用MCIWnd窗口类,必须在调用MCIWnd函数所在的源文件的前面添加vfw.h的头文件,以及编译时加入vfw32.lib库或在程序中加入下列语句:
    
#pragma comment (lib,"vfw32.lib")
          在MCIWnd窗口类中,虽然它所提供的函数并不多,但是它所提供的宏却非常多,并且基本上与MCI的底层功能相对应。
          在应用程序中使用MCIWnd窗口类的一般步骤是:
    (
1)在程序中调用MCIWndRegisterClass函数注册MCI窗口类,以便以后用CreateWindow或CreateWindowEx函数创建窗口,或者直接调用函数MCIWndCreate创建窗口。
    (
2)获得相应的窗口句柄后,就可调用MCIWndOpen宏来打开设备。
    (
3)由于MCIWnd窗口提供了相应的媒体控制按钮,因而不需要用户编写额外的代码。
    (
4)但作为技巧,用户还应该跟踪MCIWnd窗口的一些消息(如MCIWNDM_ NOTIFYSIZE)来调整MCIWnd窗口。 
10.3使用MCIWnd窗口类
    [例Ex_MCI] 利用MCIWnd窗口类在多文档应用程序中添加一个多媒体播放器。
    (
1)用MFC AppWizard(exe)创建一个多文档项目Ex_MCI,单击[Finish]。
    (
2)在StdAfx.h中放入包含文件使得应用程序能使用所有的多媒体代码。由于项目中的每一个文件已经包含了StdAfx.h,所以在其他地方就不必再包含这些多媒体文件。
    ...
    
#endif // _AFX_NO_AFXCMN_SUPPORT
    #include <vfw.h>
    
#pragma  comment (lib,"vfw32.lib")
    ...
    (
3)在CEx_MCIApp::InitInstance函数,使用MCIWndRegisterClass函数注册MCI窗口类。虽然,后面的创建窗口是直接调用函数MCIWndCreate来进行的,但还应该保证应用程序的运行系统拥有并支持MCIWnd窗口类。
    BOOL CEx_MCIApp::InitInstance()
    {   
if (!MCIWndRegisterClass())  return FALSE;
        AfxEnableControlContainer();
//使你的应用程序成为ActiveX控件包容器
        ...
    }
    (
4)在Ex_MCIView类中添加一个公共成员变量用来标识嵌入的MCIWnd窗口句柄。
    
public:
        CEx_MCIDoc* GetDocument();
        HWND m_hMyMCIWnd;
        ... 
10.3使用MCIWnd窗口类
    (
5)用ClassWizard为Ex_MCIView类中添加OnInitialUpdate消息处理函数,增加代码:
    
void CEx_MCIView::OnInitialUpdate() 
    {   CView::OnInitialUpdate();
        m_hMyMCIWnd=MCIWndCreate(m_hWnd,AfxGetInstanceHandle(),
        MCIWNDF_NOTIFYSIZE |MCIWNDF_NOERRORDLG |
        WS_CHILD|WS_VISIBLE,
NULL);
        
if (m_hMyMCIWnd==NULL)  return;
        
const CString &filename=GetDocument()->GetPathName();
        
if (filename.GetLength()>0)
        MCIWndOpen(m_hMyMCIWnd,(LPCSTR)filename,
0);
    }
    (
6)在CEx_MCIView构造函数中将成员变量m_hMyMCIWnd初始化为NULL。
    CEx_MCIView::CEx_MCIView()
    {   m_hMyMCIWnd=
NULL;
    } 
10.3使用MCIWnd窗口类
    (
7) 要添加处理该消息的代码来调整窗口的大小以便能及时更新显示。需要手动进行。在Ex_MCIView.h文件中的消息声明处添加下列代码:
    
// Generated message map functions
    protected:
        
//{{AFX_MSG(CEx_MCIView)
        ...
        
//}}AFX_MSG
        afx_msg LONG OnNotifySize(UINT wParam, LONG lParam);
        DECLARE_MESSAGE_MAP()
    (
8)在Ex_MCIView.cpp的消息入口处添加下列代码:
    BEGIN_MESSAGE_MAP(CEx_MCIView, CView)
        
//{{AFX_MSG_MAP(CEx_MCIView)
        ...
        ON_MESSAGE(MCIWNDM_NOTIFYSIZE,OnNotifySize)
        
//}}AFX_MSG_MAP
        // Standard printing commands
        ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
        ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
        ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
    END_MESSAGE_MAP() 
10.3使用MCIWnd窗口类
    (
9)为CEx_MCIView类添加该消息的处理函数OnNotifySize,代码:
    LONG CEx_MCIView::OnNotifySize(UINT wParam, LONG lParam)
    {   CRect rc;
        CFrameWnd* pParent=GetParentFrame();
        
if (m_hMyMCIWnd)
        {   ::GetWindowRect(m_hMyMCIWnd,rc);
            pParent->CalcWindowRect(rc,CWnd::adjustBorder);
            CSize size(rc.Width(),rc.Height());
            
if (GetExStyle()&WS_EX_CLIENTEDGE)
            {   size.cx+=
4;
                size.cy+=
4;
            }
            pParent->SetWindowPos(
NULL,0,0,size.cx,size.cy,
            SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE);
        }
        
else 
        {   pParent->SetWindowPos(
NULL,0,0,200,160,
            SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE);
        }
        
return 1;
    } 
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
计算机与信息技术学院设计性实验报告
专业:              年级/班级:             2010—2011学年第二学期
课程名称    多媒体技术   指导教师    
本组成员
学号姓名    
实验地点        实验时间    
项目名称    利用MCI在VC++环境下设计一个播放器    实验类型    设计性
一、  实验目的:
熟悉MCI,并能利用MCI编程在visual c++环境设计出一个音乐播放器,掌握使用高级语言进行多媒体编程的功能。
二、  实验仪器或设备:
一台安装有visual c++的计算机。
三、  总体设计(设计原理、设计方案及流程等):
①   在visual c++环境下设计出一个音乐播放器的界面:具有打开、播放,前进、后退、暂停或继续、停止的功能;
②   修改各个控件的属性,并为其添加代码;
③对该音乐播放器编译--运行。
四、  实验步骤(包括主要步骤、代码分析等)
(一):创建MFC应用程序:
打开visual c++软件,选择“文件”—“新建”新建一个应用程序文档MFC AppWizard[exe],将工程命名为player。
(二)编辑对话框:
在工作区内,设计出一个音乐播放器的界面,添加按钮控件:打开、播放,前进、后退、暂停或继续、停止,后再添加一个滑动条控件。
(三)为各个控件依次添加以下对应的代码:
void CMusicplayerDlg::OnBUTTONOpen() 
{   CFileDialog file(TRUE,
"","", OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_FILEMUSTEXIST, 
        
"Wave Audio(*.wav)|*.wav|MIDI(*.mid)|*.mid|mp3(*.mp3)|*.mp3|所有文件(*.*)|*.*|");
    
if(file.DoModal() == IDOK)
    {       strFileName = file.GetPathName();
        strFileExt = file.GetFileExt(); 
    }}
void CMusicplayerDlg::OnBUTTONPlay() 
{   bPause = TRUE; 
//初始化
    SetTimer(133NULL); //为滑动条启动定时器,频繁发送定时消息
    mciSendCommand(m_wDeviceID, MCI_CLOSE, NULLNULL); //保证总是重新播放
    //打开设备
    MCI_OPEN_PARMS mciOpen; 
    mciOpen.lpstrElementName = strFileName.GetBuffer(strFileName.GetLength());
    mciSendCommand(
NULL, MCI_OPEN, MCI_OPEN_ELEMENT, (DWORD)&mciOpen); //发送打开相关设备的命令
    //检测播放总长度
    m_wDeviceID = mciOpen.wDeviceID; //得到打开的设备的ID
    MCI_STATUS_PARMS mciStatusParms;
    mciStatusParms.dwItem = MCI_STATUS_LENGTH;
    mciSendCommand(m_wDeviceID, MCI_STATUS, MCI_WAIT|MCI_STATUS_ITEM, (DWORD)&mciStatusParms); 
//发送状态命令
    m_lLength = mciStatusParms.dwReturn;
    
//播放设备
    MCI_PLAY_PARMS mciPlay;
    mciSendCommand(m_wDeviceID, MCI_PLAY, 
NULL, (DWORD)&mciPlay);
    
//滑动还原到最左端
    m_pSlider->SetRange(0, m_lLength); //设置滑动条范围
    m_pSlider->SetPos(0); //播放时滑动条总是在最左端    
}
void CMusicplayerDlg::OnBUTTONPrevious () 
{       bPause = TRUE;
    
//记录当前位置
    MCI_STATUS_PARMS mciStatusParms;
    mciStatusParms.dwItem = MCI_STATUS_POSITION;
    mciSendCommand(m_wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD)&mciStatusParms); 
    dCurrentPosition = mciStatusParms.dwReturn; 
//取得当前位置的信息
    MCI_PLAY_PARMS mciPlayParms;
    
if(dCurrentPosition <= (m_lLength / 16)) //当前位置不足一个后退步
    {       //发送后退到文件开始点的命令
        mciSendCommand(m_wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, NULL); 
        mciSendCommand(m_wDeviceID, MCI_PLAY, 
NULL, (DWORD)&mciPlayParms);
    }   
else //当前位置满足后退一步尚有余
    {       //从当前位置减小十六分之一的长度
        mciPlayParms.dwFrom = dCurrentPosition - (DWORD)(m_lLength / 16);       //发送从指定位置开始播放的命令
        mciSendCommand(m_wDeviceID, MCI_PLAY, MCI_FROM, (DWORD)&mciPlayParms);
    }}
void CMusicplayerDlg::OnBUTTONNext () 
{       bPause = TRUE;
    
//记录当前位置
    MCI_STATUS_PARMS mciStatusParms;    
    mciStatusParms.dwItem = MCI_STATUS_POSITION;
    mciSendCommand(m_wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD)&mciStatusParms); 
    dCurrentPosition = mciStatusParms.dwReturn; 
//取得当前位置的信息
    MCI_PLAY_PARMS mciPlayParms;
    
if((m_lLength - dCurrentPosition) <= (m_lLength / 16)) //不足一个前进步
    {       //发送向前跳转到文件尾部的命令
        mciSendCommand(m_wDeviceID, MCI_SEEK, MCI_SEEK_TO_END, NULL); 
        mciSendCommand(m_wDeviceID, MCI_PLAY, 
NULL, (DWORD)&mciPlayParms); 
    }   
else //满足一个前进步尚有余
    {       //从当前位置增加十六分之一的长度
        mciPlayParms.dwFrom = dCurrentPosition + (DWORD)(m_lLength / 16);       //发送从指定位置开始播放的命令
        mciSendCommand(m_wDeviceID, MCI_PLAY, MCI_FROM, (DWORD)&mciPlayParms);
    }}
void CMusicplayerDlg::OnBUTTONPauRes () 
{       
if(bPause)
    {       bPause = FALSE;
        MCI_GENERIC_PARMS mciPause; 
        mciSendCommand(m_wDeviceID, MCI_PAUSE, 
NULL, (DWORD)&mciPause); 
    }   
else
    {       bPause = TRUE;
        
if(strFileExt == "mid" || strFileExt == "MID")
        {           
//记录当前位置
            MCI_STATUS_PARMS mciStatusParms;
            mciStatusParms.dwItem = MCI_STATUS_POSITION;
            mciSendCommand(m_wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD)&mciStatusParms); 
//发送状态命令
            dCurrentPosition = mciStatusParms.dwReturn; //取得当前位置的信息
            MCI_PLAY_PARMS mciPlayParms;
            mciPlayParms.dwFrom = dCurrentPosition; 
//从当前位置
            mciSendCommand(m_wDeviceID, MCI_PLAY, MCI_FROM, (DWORD)&mciPlayParms); //发送从指定位置开始播放的命令
        }
        
else //不是midi,则直接发送MCI_RESUME
        {           //发送继续播放这个设备的命令
            MCI_GENERIC_PARMS mciResume; 
            mciSendCommand(m_wDeviceID, MCI_RESUME, 
NULL, (DWORD)&mciResume); 
        }   }   }
void CMusicplayerDlg::OnBUTTONStop () 
{
        mciSendCommand(m_wDeviceID, MCI_STOP, 
NULLNULL); 
    KillTimer(
1); //销毁定时器,使其对滑动条的设置无效
        m_pSlider->SetPos(0); //将滑动条放在最左端
}
void CMusicplayerDlg::OnTimer(UINT nIDEvent) 
{           MCI_STATUS_PARMS mciStatusParms;
    mciStatusParms.dwItem = MCI_STATUS_POSITION;
    mciSendCommand(m_wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD)&mciStatusParms); 
    dCurrentPosition = mciStatusParms.dwReturn; 
//取得当前位置的信息     m_pSlider->SetPos(dCurrentPosition); //频繁设置滑动条位置(每次定时消息一到)
    CDialog::OnTimer(nIDEvent);
}
(四)编译、链接并运行程序:
选择菜单栏Bulid下的compile-bulid-execute对程序进行编译、链接、运行。
五、  结果分析与总结
结果分析:对以上程序进行运行,可见,实验结果是正确的,实符合要求的,也达到了实验的目的。
总结:通过此次实验,我学会了如何使用MCI在visual C++环境下制作一个音乐播放器,不仅再次熟悉了visual c++环境,而且也牢固的掌握了MCI的编程接口知识,使我受益匪浅。

wDeviceID = mci_Open_parmasa.wDeviceID;

这句要用在    mcicommand(mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_ELEMENT ,(DWORD)&mci_Open_Parmsa))的后面才有意义。