/* 利用业余时间,抽空将音乐播放器的部分代码进行了注释,详解。希望晓伟能够帮助下期初看视频不动代码意思,照抄照搬的鹏友们!不足之处还望海涵!!!(很希望和志同道合的鹏友们一起畅聊,一起学习,共同进步!!!QQ:1693672542) */ #include "stdafx.h" #include <windows.h> #include <windowsx.h> #include <commdlg.h> #include <mmsystem.h> #include "resource.h" #include "MainDlg.h" #include<string.h> // PathFindExtension();函数的使用必须有这个头文件 #include <shlwapi.h> #pragma comment(lib, "shlwapi.lib")
//消息回调函数(实现消息的处理) BOOL WINAPI Main_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { /* 对 HANDLE_MSG() 消息分流器 的一点理解 windowsx.h中有以下宏定义: #define HANDLE_MSG(hwnd, message, fn) \ case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn)) #define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L)
当我们写下下面的代码时: HANDLE_MSG(hWnd, WM_CREATE, pWindow->OnCreate); 根据第一条宏定义会转化为: case (WM_CREATE) : return HANDLE_WM_CREATE(((hwnd), (wParam), (lParam), (pWindow->OnCreate))
接下来使用第二条宏定义来替换,就成这样的了: case (WM_CREATE) : return pWindow->OnCreate((hwnd), (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L)
##的作用是将两个字符串连接起来 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// WM_INITDIALOG与WM_CREATE的区别: WM_CREATE是所有窗口都能响应的消息,表明本窗口已经创建完毕. 在响应WM_CREATE消息响应函数的时候,对话框及子控件还未创建完成,亦是说只是通知系统说要开始创建窗口了,这个消息响应完之后,对话框和子控件才开始创建。 因此在此消息响应函数中无法对控件进行修改和初始化。 而WM_INITDIALOG消息响应函数是在程序运行时,当其对话框和子控件全部创建完毕,将要显示内容的时候发送的消息。 因此可以在WM_INITDIALOG消息响应函数中添加对编辑框控件的初始化和修改
*/ switch(uMsg) { //HANDLE_MSG() 消息分流器 HANDLE_MSG(hWnd, WM_INITDIALOG, Main_OnInitDialog); HANDLE_MSG(hWnd, WM_COMMAND, Main_OnCommand); HANDLE_MSG(hWnd,WM_CLOSE, Main_OnClose); } return FALSE; }
//WM_INITDIALOG 消息是对话框才能收到的消息,表明对话框及其所有子控件都创建完毕了。 //这个状态肯定是 调用显示对话框的函数之前。 BOOL Main_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) { return TRUE; }
//处理菜单项被点击时候的消息 void Main_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { switch(id) { case ID_FILEOPEN://点击"打开按钮"触发的消息 { /* OPENFILENAME结构包含了GetOpenFileName和GetSaveFileName函数 用来初始化打开或另存为对话框的信息。在用户关闭对话框后, 系统返回关于用户的选择信息到这个结构中。 */ OPENFILENAME ofn;//创建一个结构体对象 char szFile[MAX_PATH];//char szFile[260]; ZeroMemory(&ofn,sizeof(ofn)); //指定这个结构的大小,以字节为单位。 ofn.lStructSize = sizeof(ofn);
/* lpstrFile:指向包含初始化文件名编辑控件使用的文件名的缓冲。 如果不需要初始值,这个缓冲的第一个字符必须是NULL。 当GetOpenFileName或GetSaveFileName函数返回成功时, 这个缓冲包含驱动器,路径,文件名,及所选择的文件的扩展名。 */ ofn.lpstrFile = szFile; ofn.lpstrFile[0] = TEXT('\0');
/* nMaxFile:指定lpstrFile缓冲的大小,以TCHARs为单位。 对于ANSI版本,是字节的个数;对于Unicode版本,是字符的个数。 这个缓冲必须足够存储路径和文件名字符串,包含结尾的null字符。 如果缓冲太小,GetOpenFileName和GetSaveFileName函数 返回假(FALSE)缓冲最小应该在256个字符长 */
ofn.nMaxFile = sizeof(szFile); /* lpstrFilter:指向一对以空字符结束的过滤字符串的一个缓冲。 缓冲中的最后一个字符串必须以两个NULL字符结束。 第一个字符串是过滤器描述的显示字符串(例如,“文本文件”), 第二个字符指定过滤样式(例如,“*.TXT”)。 要为一个显示字符串指定多个过滤样式, 使用分号(“;”)分隔样式(例如,“*.TXT;*.DOC;*.BAK”)。 一个样式字符串中可以包含有效的文件名字字符及星号(*)通配符。 不能在样式字符串中包含空格。系统不能改变过滤器的次序。 它按lpstrFilter指定的次序显示在文件类型组合框中。 如果lpstrFilter是NULL,对话框不能显示任何过滤器。 */ ofn.lpstrFilter = TEXT("ALL\0*.*\0txt\0*.txt\0"); /* lpstrFilterIndex:指定在文件类型控件中当前选择的过滤器的索引。 缓冲指向被lpstrFilter包含的一对定义了的过滤器的字符串。 过滤器的第一对字符串的索引值为1,第二对为2,等等。 0索引指出是通过lpstrCustomFilter指定的定制过滤器 。你可以为对话框指定一个索引作为最初的过滤器描述及过滤器样式。当用户选择了一个文件时,nFilterIndex返回当前显示的过滤器的索引。 */ ofn.nFilterIndex = 1;
//lpstrFileTitle:指向接收选择的文件的文件名和扩展名的缓冲(不带路径信息)。 //这个成员可以是NULL。 ofn.lpstrFileTitle = NULL; /* nMaxFileTitle:指定lpstrFileTitle缓冲的大小,以TCHARs为单位。 对于ANSI版本,是字节的个数;对于Unicode版本,是字符的个数。 如果lpstrFileTitle是NULL,这个成员被忽略。 */ ofn.nMaxFileTitle = 0;
/* 指向以空字符结束的字符串,可以在这个字符串中指定初始目录。 Pointer to a null terminated string that can specify the initial directory. 在不同的平台上,为选择初始目录有不同的运算法则。 */ //如果lpstrInitialDir是NULL并且lpstrFile包含了一个路径,那么这个路径就是初始目录。 ofn.lpstrInitialDir = NULL; ofn.hwndOwner = hwnd;//自学能力、探索能力、猜测能力
/*Flags:位标记的设置,你可以使用来初始化对话框。当对话框返回时, 它设置的这些标记指出用户的输入。这个成员可以是下列标记的组合: OFN_EXPLORER 指出任何打开或另存为对话框使用新的Explorer风格的用户化模块。
OFN_PATHMUSTEXIST 指定用户仅能输入的路径和文件名。 如果这个标记被使用并且用户在文件名输入字段中键入了一个用效的路径和文件名, 对话框函数显示一个等待消息。
OFN_FILEMUSTEXIST 指定用户仅可以在文件名登录字段中输入已存在的文件的名字。 如果这个标记被指定的并且用户输入了一个无效的名字,对话框程序显示一个等待消息框。 如果这个标记被指定,OFN_PATHMUSTEXIST标记也被使用。
*/ ofn.Flags = OFN_EXPLORER |OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; if (GetOpenFileName(&ofn)) { char* string={0}; TCHAR shortPath[MAX_PATH];//存储短路径字符型数组 GetShortPathName(szFile,shortPath,sizeof(shortPath)); TCHAR fname[MAX_PATH+10];//用于存放文件名 wsprintf(fname,"%s",shortPath); MessageBox(hwnd,fname,fname,MB_OK);//弹出提示框,显示文件的最短路径 //MessageBox(hwnd,szFile,szFile,MB_OK); //MessageBox(hwnd,shortPath,shortPath,MB_OK); FILE *stream; LPTSTR pszExtension; GetModuleFileName(NULL,fname,2048); pszExtension = PathFindExtension(fname); string=(char*)pszExtension; if(string==".txt") { FILE * fp=NULL; char line[256];//此处用char而不是TCHAR fp=fopen(fname,"r"); fgets(line,sizeof(line),fp); fclose(fp);//关闭文件 fp=NULL;//需要指向NULL,否则会指向原打开文件地址 SetDlgItemText(hwnd,IDC_EDIT1,TEXT(line));//在文本框中输出 } else { MessageBox(hwnd,TEXT("cannot open the file!"),TEXT("ERROR"),MB_OK|MB_ICONERROR); exit(0);//终止正在执行的程序 } //MessageBox(hwnd,szFile,szFile,MB_OK);//获得文件路径 } } break;
//如果点击了播放音乐菜单项 case ID_MUSICPLAY: { OPENFILENAME ofn; char szFile[MAX_PATH];//字符型数组 /* ZeroMemory宏用0来填充一块内存区域。 为了避免优化编译器的意外的影响,请使用SecureZeroMemory函数。 void ZeroMemory( PVOID Destination, SIZE_T Length ); 参数: Destination :指向一块准备用0来填充的内存区域的开始地址。 Length :准备用0来填充的内存区域的大小,按字节来计算。 */ ZeroMemory(&ofn,sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.lpstrFile = szFile;//设置文件初始时候缓冲区的大小 ofn.lpstrFile[0] = TEXT('\0'); ofn.nMaxFile = sizeof(szFile); ofn.lpstrFilter = TEXT("ALL\0*.*\0txt\0*.txt\0"); ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; /* windows的窗口大致有三类,对应的术语是: 层叠窗口(layered window)、弹出式窗口(popup window)和子窗口(child window)。 另外有两个术语:父窗口(parent window)和所有者窗口(owner window) 父窗口是相对于子窗口而言的。 所有者窗口是相对于弹出式窗口而言的。 hwndOwner就是指目录对话框的所有者窗口是谁 因为目录对话框是弹出式对话框,因此它所使用的术语是所有者窗口而不是父窗口。 行为表现: 1)子窗口只能活动与父窗口的客户区中,绝对不可能跑出客户区。 2)相对于子窗口而言的父窗口,如果他的上面没有其他父窗口了, 那么他就是一种层叠窗口。顾名思义,层叠窗口之间是可以互相叠在一起的。 3)弹出式窗口其实就是一种模式对话框,如果他有所有者窗口的话, 那么当弹出式窗口没有被关闭时,所有者窗口是无法被我们激活的(即你点一下窗口中的按钮没反应,标题栏是浅色的)。 当弹出式窗口未指定所有者窗口的话,那它的行为表现和层叠窗口差不多。就是弹出式窗口没有被关闭的话,也不会影响到其他窗口的活动。
因此,当BROWSEINFO结构的hwndOwner等于NULL的话,你可以看下目录对话框打开后,并不会影响到我们自己窗口的活动 */ //hwndOwner指定了我们自己的窗口的话,那么当目录对话框打开后,我们的窗口是无法活动的。 ofn.hwndOwner = hwnd; ofn.Flags = OFN_EXPLORER |OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; if (GetOpenFileName(&ofn)) { //MessageBox(hwnd,szFile,szFile,MB_OK); //MessageBox(NULL,szFile,"",MB_OK);//效果同上 TCHAR shortPath[MAX_PATH]; GetShortPathName(szFile,shortPath,sizeof(shortPath)); TCHAR cmd[MAX_PATH+10]; wsprintf(cmd,"play %s",shortPath); mciSendString(cmd,"",0,NULL); //实现播放音乐的功能 } } break; default: break; } }
//关闭窗口 void Main_OnClose(HWND hwnd) { EndDialog(hwnd, 0); }
|
|