本文由BlueCoder编写 转载请说明出处:
http://blog.csdn.net/crocodile__/article/details/10832337
我的邮箱:bluecoder@yeah.net 欢迎大家和我交流编程心得
我的微博:BlueCoder_黎小华 欢迎光临^_^
前段时间,在学习中科院杨老师的教学视频时,他说了一句话:
"我很反对百八十行的教学程序,要来就来一个完整的程序"
对此,我很是赞同。所谓真刀真枪的做了,你才会发现其中的奥秘——然而,能写一个完整的程序,首先你肯定是理解掌握了相关的技术,其次你享受了一个完整开发的基本"旅程"
因此,除非是很重要的技术,我会仅仅用一个几十行代码的程序加以说明,否则我就会用一个完整的程序来实现一些基本功能——通过这个完整的程序来掌握相关技术,我感觉很好……
好了,F话不多说了,切入正题
……
*****************************************************程序效果***********************************************************
还是先来看一看鄙人写的简易播放器实现的效果吧:
可以看到,它既可以播放mp3音频文件,也可以播放avi视频文件
*****************************************************实现细节***********************************************************
(1)利用win32提供的MCI来播放音频或者视频文件
(2)用一个文件浏览对话框来提供文件选择功能
(3)做一个标准菜单——包含快捷键
*****************************************************代码详解***********************************************************
(1)创建一个文件浏览对话框
1>初始化OPENFILENAME结构体变量,它的成员有很多,不过一般只有以下几个很常用(其余的,读者可以参见msdn):
lStructSize—— 结构体变量大小,用sizeof(OPENFILENAME)指定
hwndOwner—— 拥有它的窗口句柄
lpstrFilter—— 文件过滤
lpstrFile—— 保存文件绝对路径
nMaxFile—— 绝对路径的最大长度
lpstrFileTitle——对话框标题
nMaxFileTitle— 对话框标题的最大长度
Flags———— 标示
它的初始化以及相应操作,我是在一个函数中实现的——openFileDialog,具体代码如下:
//打开文件浏览对话框 VOID openFileDialog(HWND hOwner) { static TCHAR szFilePath[MAX_PATH], szTitleName[MAX_PATH]; OPENFILENAME ofn; TCHAR szFileFilter[] = TEXT("Media Files(*.avi;*.mpg;*.mpeg;*.asf;*.wmv;*.mp2;*.mp3)\0")\ TEXT("*.avi;*.mpg;*.mpeg;*.asf;*.wmv;*.mp2;*.mp3\0")\ TEXT("Movie File(*.avi;*.mpg;*.mpeg)\0*.avi;*.mpg;*.mpeg\0")\ TEXT("Windows Media File(*.asf;*.wmv)\0*.asf;*.wmv\0")\ TEXT("Audio File(*.mp2;*.mp3)\0*.mp2;*.mp3\0"); //初始化ofn结构体变量 ZeroMemory(&ofn, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hOwner; ofn.lpstrFilter = szFileFilter; ofn.lpstrFile = szFilePath; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = szTitleName; ofn.nMaxFileTitle = MAX_PATH; ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST; //打开文件浏览对话框 if(GetOpenFileName(&ofn)) { int i=0, j=0, k=0; /* 因为ASCII的字符串中, '\'只能以'\\'才能识别, 所以还得自行在'\'之后添加一个'\' */ while(szFilePath[i]) { szFileDir[j++] = szFilePath[i]; if(szFileName[i++] == '\\') szFileDir[j++] = '\\'; if(i >= ofn.nFileOffset) szFileName[k++] = szFilePath[i]; } szFileDir[j] = '\0'; szFileName[k] = '\0'; //先停止当前播放的视、音频文件 mciSendString("Close movie", NULL, 0, 0); openFile(hOwner); if(!isMp) { //打开视频文件后 , 先短暂播放一截 , 给你一个预览的效果 mciSendString("Play movie", NULL, 0, 0); mciSendString("Pause movie", NULL, 0, 0); } //设置窗口标题为当前打开文件的完整路径 SetWindowText(hOwner, szFileDir); isEnable = TRUE;//标记菜单项可执行 } }
(2)MCI代码细节
1>打开利用MCI关联系统设备打开相应文件,这需要使用到MCI_DGV_OPEN_PARMS,来看看msdn:
typedef struct { DWORD_PTR dwCallback; //就是窗口句柄,用于MCI_NOTIFY这个标示 UINT wDeviceID; //设备ID,一般为0 LPSTR lpstrDeviceType; //设备类型 LPSTR lpstrElementName; //打开文件的绝对地址 LPSTR lpstrAlias; //设备别名 DWORD dwStyle; //窗口风格(如果你想在主窗口中播放, 需要设定为子窗口风格WS_CHILD) HWND hWndParent; //父窗口句柄 } MCI_DGV_OPEN_PARMS;
2>初始化好这个变量后,就要通知系统打开相应设备,用mciSendCommand这个函数,还是先来看看msdn:
MCIERROR mciSendCommand( MCIDEVICEID IDDevice, //设备ID, 一般为0 UINT uMsg, //MCI消息 DWORD fdwCommand, //MCI命令 DWORD_PTR dwParam //指向刚刚初始化的结构体变量 );
3>下面需要创建一个窗口用于播放视频,使用MCI_DGV_STATUS_PARMS结构体:typedef struct { DWORD_PTR dwCallback; //也是窗口句柄 , 同上 DWORD dwReturn; //播放视频的窗口句柄 DWORD dwItem; //下面不是很重要,一般可以不管 DWORD dwTrack; LPSTR lpstrDrive; DWORD dwReference; } MCI_DGV_STATUS_PARMS;
4>我写了一个函数——openFile打开文件,用于实现上述功能,具体如下://打开音频或视频文件 VOID openFile(HWND hParent) { MCI_DGV_OPEN_PARMS mciOpen;//MCI打开参数结构体 MCI_DGV_STATUS_PARMS mciStatus;//MCI状态参数结构体 UINT uDeviceID;//设备ID RECT rClient;//父窗口客户区大小 mciStatus.dwItem=MCI_DGV_STATUS_HWND; //初始化mciOpen以及打开avi文件 ZeroMemory(&mciOpen,sizeof(mciOpen)); mciOpen.dwCallback =(DWORD)hParent; mciOpen.lpstrAlias = TEXT("movie");//设备别名 mciOpen.lpstrElementName= szFileDir;//avi文件地址 mciOpen.hWndParent = hParent;//父窗口 mciOpen.dwStyle = WS_CHILD;//窗口风格 mciSendCommand(0 , MCI_OPEN, MCI_OPEN_ALIAS | MCI_OPEN_ELEMENT | MCI_DGV_OPEN_PARENT | MCI_DGV_OPEN_WS, (DWORD)&mciOpen); //获取播放avi视频的子窗口hVideo uDeviceID=mciOpen.wDeviceID; mciSendCommand(uDeviceID, MCI_STATUS , MCI_STATUS_ITEM, (DWORD)&mciStatus); hVideo=(HWND)mciStatus.dwReturn;//获取播放视频的窗口句柄 //重绘主窗口 GetClientRect(hParent, &rClient); SendMessage(hParent, WM_SIZE, 0, MAKELONG(rClient.right - rClient.left, rClient.bottom - rClient.top)); //判断当前打开的文件是否是音频文件 if(strstr(szFileDir, TEXT("mp3")) || strstr(szFileDir, TEXT("mp2"))) { isMp = TRUE; } }
(3)做一个标准菜单
这个和上次讲的一样,只不过加了"快捷键",菜单的创建和加载就不多说了,主要讲一下快捷键的用法
我们日常些一般程序的消息循环代码如下:
while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
使用键盘快速键之后修改的代码:hAccel = LoadAccelerators (hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR)); while(GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator (hwnd, hAccel, &msg)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } }
P先生关于它的说明是:
TranslateAccelerator函数将键盘消息翻译成WM_COMMAND或WM_SYSCOMMAND,当有键盘消息来的时候,该函数在加速键表中寻找句柄为hAccel的匹配值,如果找到匹配值,就会调用句柄为hwnd的窗口回调函数
你不需要其它代码来维护,这个函数帮你完成了"快捷键的映射"
***************************************************************************************************************
ok,代码大致讲述到此为止,还有很多细节不便在此细说,读者可以详细拜读我上传的源代码,内含详细注释
PS:可能你会发现我的程序在你的电脑上不能播放视频,这是因为你电脑上没有avi视频的解码器,MCI不能识别
解决方法就是安装我上传资源的XviD.rar中的解码程序
点击下载源代码及相应资源