核心代码:
#include //滚动条控制时包含头文件
#include //文件夹选择对话框包含头文件

TCHAR szFileName[80][MAX_PATH];//播放列表
int iNum = 0;//音乐数
int iPlay = 0;//播放状态:0未播放 1正在播放 2暂停
int iPlayListIndex = 0;//播放列表索引
int iLength;//播放文件时长秒数

Main_Proc处理里添加:
HANDLE_MSG(hWnd, WM_HSCROLL, Main_OnHScroll);//水平滚动条消息。WM_VSCROLL垂直滚动条消息。

Main_OnInitDialog初始化添加:
//音量滚动条
//设置滚动条取值范围
//参考:http://www.rupeng.com/forum/redirect.php?fid=32&tid=601&goto=nextoldset
//http://hi.baidu.com/mowm/blog/item/c76d07ee77e5101efcfa3cd0.html
SendMessage(GetDlgItem(hwnd, IDC_TRBVOLUME), TBM_SETRANGEMIN, TRUE, 0);//最小值
SendMessage(GetDlgItem(hwnd, IDC_TRBVOLUME), TBM_SETRANGEMAX, TRUE, 1000);//最大值
SendMessage(GetDlgItem(hwnd, IDC_TRBVOLUME), TBM_SETPOS, TRUE, 1000);//当前位置

////////////////////////////////////////////////////////////////////////////////
// Main_OnCommand
void Main_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
switch(id)
{
case IDC_BTNOPENFILES://添加文件按钮
OpenFiles(hwnd);
break;
case IDC_BTNSELECTFOLDER:
SelectFolder(hwnd);
break;
case IDC_BTNPLAY://播放暂停按钮
if(0 == iPlay)//未播放
{
//获得选中项播放列表索引
iPlayListIndex = SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_GETCURSEL, 0, 0);
//播放选中项,改变播放状态。
Play(hwnd, iPlayListIndex);
//改变按钮显示文字
SetWindowText(hwndCtl, "暂停");
}
else if(1 == iPlay)//正在播放
{
//暂停正在播放文件
mciSendString("pause OpenMusicFile", (LPTSTR)NULL, 0, NULL);
//改变播放状态
iPlay = 2;
//改变按钮显示文字
SetWindowText(hwndCtl, "播放");
}
else//暂停
{
//恢复暂停播放文件
mciSendString("play OpenMusicFile", (LPTSTR)NULL, 0, NULL);
//改变播放状态
iPlay = 1;
//改变按钮显示文字
SetWindowText(hwndCtl, "暂停");
}
break;
case IDC_BTNPREV://上一首
//获得上一首播放列表索引
iPlayListIndex = SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_GETCURSEL, 0, 0) - 1;
if(iPlayListIndex >= 0)//索引在范围内
{
Play(hwnd, iPlayListIndex);
//设置上一首为选中项
SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_SETCURSEL, iPlayListIndex, 0);
SetWindowText(GetDlgItem(hwnd, IDC_BTNPLAY), "暂停");
}
break;
case IDC_BTNNEXT://下一首
iPlayListIndex = SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_GETCURSEL, 0, 0) + 1;
if(iPlayListIndex < iNum)
{
Play(hwnd, iPlayListIndex);
SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_SETCURSEL, iPlayListIndex, 0);
SetWindowText(GetDlgItem(hwnd, IDC_BTNPLAY), "暂停");
}
break;
case IDC_LST1://列表消息
switch(codeNotify)
{
case LBN_SELCHANGE://选中项改变
//获得选中项播放列表索引
int iChange = SendMessage(hwndCtl, LB_GETCURSEL, 0, 0);
if(iChange != iPlayListIndex)//索引改变
{
iPlay = 0;//新文件未播放
SetWindowText(GetDlgItem(hwnd, IDC_BTNPLAY), "播放");
}
else//索引未改变
{
iPlay = 1;//文件正在播放
SetWindowText(GetDlgItem(hwnd, IDC_BTNPLAY), "暂停");
}
break;
case LBN_DBLCLK://双击某项
iPlayListIndex = SendMessage(hwndCtl, LB_GETCURSEL, 0, 0);
Play(hwnd, iPlayListIndex);
SetWindowText(GetDlgItem(hwnd, IDC_BTNPLAY), "暂停");
break;
default:break;
}
break;
default:break;
}
}

void Main_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos)//固定格式?
{
if(hwndCtl == GetDlgItem(hwnd, IDC_TRBVOLUME))
SetVolume(hwnd);
else
SetPlayProcess(hwnd);
}

void OpenFiles(HWND hwnd)
{
OPENFILENAME ofn;
TCHAR szOpenFileNames[80*MAX_PATH];//文件路径
TCHAR szPath[MAX_PATH];//基路径
TCHAR* p;
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.lpstrFile = szOpenFileNames;
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szOpenFileNames);
ofn.lpstrFilter = TEXT("音乐文件(mp3、wma、wav)\0*.mp3;*.wma;*.wav\0所有文件(*.*)\0*.*\0");
ofn.Flags = OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if(GetOpenFileName(&ofn))
{
//单个文件的保存形式为:绝对路径\0
//多个文件的保存形式为:基路径\000文件一\000文件二\0
//注意路径"\"的转义为"\\"
//把路径复制到szPath
//参考资料:http://blog.csdn.net/xuminggang/archive/2009/05/21/4206010.aspx
lstrcpyn(szPath, szOpenFileNames, ofn.nFileOffset+1);
//根据单个和多个文件不同的保存形式,多文件基路径需加"\\"。
szPath[ofn.nFileOffset-1] = '\\';
//把指针移到第一个文件
p = szOpenFileNames + ofn.nFileOffset;
iPlayListIndex = iNum;//加入的第一个文件
while(*p)
{
lstrcat(szFileName[iNum], szPath); //基路径
lstrcat(szFileName[iNum], p); //基路径+文件=绝对路径
//加入列表
//ListBox参考:http://www.cnitblog.com/netssfy/archive/2007/06/12/28347.html
SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_ADDSTRING, 0, (LPARAM)p);
p += lstrlen(p) +1; //移至下一个文件
iNum++; //增加音乐数,移动准备接收下一个文件路径。
}
//设置选中项
SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_SETCURSEL, (WPARAM)iPlayListIndex, 0);
//播放选中项
Play(hwnd, iPlayListIndex);
}
}

void Play(HWND hwnd, int iPlayListIndex)
{
TCHAR szMCIInfo[256]; //MCI操作返回信息
TCHAR szShortFileName[MAX_PATH]; //短文件名
ZeroMemory(szShortFileName, sizeof(szShortFileName));
//关闭正在播放的文件
//OpenMusicFile是通过MCI Command String中alias设置文件别名
mciSendString("close OpenMusicFile", szMCIInfo, sizeof(szMCIInfo), NULL);
//参考:http://www.programfan.com/doc/vbapi/GetShortPathName.htm
//http://topic.csdn.net/t/20060926/15/5049254.html
//否则播放不了路径带空格的文件
GetShortPathName(szFileName[iPlayListIndex], szShortFileName, sizeof(szShortFileName));
//MCI Command String
//参考:http://tieba.baidu.com/f?kz=26410588
TCHAR szCMD[2*MAX_PATH];
wsprintf(szCMD, "open %s alias OpenMusicFile", szShortFileName);
//打开文件
mciSendString(szCMD, szMCIInfo, sizeof(szMCIInfo), NULL);
//播放文件
mciSendString("play OpenMusicFile", szMCIInfo, sizeof(szMCIInfo), NULL);
mciSendString("status OpenMusicFile length", szMCIInfo, sizeof(szMCIInfo), NULL);//szMCIInfo获得播放时长毫秒数
iLength = atoi(szMCIInfo)/1000;//播放时长秒数
//设置进度滚动条取值范围
SendMessage(GetDlgItem(hwnd, IDC_TRBPROCESS), TBM_SETRANGEMIN, TRUE, 0);
SendMessage(GetDlgItem(hwnd, IDC_TRBPROCESS), TBM_SETRANGEMAX, TRUE, iLength);
//设置定时器,更新进度滚动条。
SetTimer(hwnd, 1, 1000, PlayProcess);
//设置音量
SetVolume(hwnd);
//改变播放状态
iPlay = 1;
//改变按钮显示文字
SetWindowText(GetDlgItem(hwnd, IDC_BTNPLAY), "暂停");
}

void SetVolume(HWND hwnd)
{
//获得音量滚动体当前位置
int iVolume = SendMessage(GetDlgItem(hwnd, IDC_TRBVOLUME), TBM_GETPOS, 0, 0);
//设置音量
TCHAR szVolume[256];
wsprintf(szVolume, "setaudio OpenMusicFile volume to %d", iVolume);
mciSendString(szVolume, (LPTSTR)NULL, 0, 0);
}

void SetPlayProcess(HWND hwnd)
{
if(0 == iPlay)//未播放时不能拖动滚动条
SendMessage(GetDlgItem(hwnd, IDC_TRBPROCESS), TBM_SETPOS, TRUE, 0);
else if(1 == iPlay)//只能在播放时拖动进度滚动条
{
TCHAR szPlayProcess[256];
int iPosition = SendMessage(GetDlgItem(hwnd, IDC_TRBPROCESS), TBM_GETPOS, 0, 0)*1000;//拖动位置毫秒数
wsprintf(szPlayProcess, "play OpenMusicFile from %d", iPosition);
mciSendString(szPlayProcess, (LPTSTR)NULL, 0, 0);
}
}

void CALLBACK PlayProcess(HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)
{
TCHAR szMCIInfo[256];//MCI操作返回信息
mciSendString("status OpenMusicFile position", szMCIInfo, sizeof(szMCIInfo), NULL);//szMCIInfo获得播放当前位置毫秒数
int iPosition = atoi(szMCIInfo)/1000;//播放当前位置秒数
//更新播放时间
TCHAR* szBuffer;
FormatTime(iLength, iPosition, szBuffer);
SetWindowText(GetDlgItem(hwnd, IDC_STCTIME), szBuffer);
SendMessage(GetDlgItem(hwnd, IDC_TRBPROCESS), TBM_SETPOS, TRUE, iPosition);//设置进度滚动条位置
if(iPosition == iLength)//结束
{
mciSendString("close OpenMusicFile", (LPTSTR)NULL, 0, 0);
iPlay = 0;
SetWindowText(GetDlgItem(hwnd, IDC_BTNPLAY), TEXT("播放"));
}
}

void FormatTime(int iLength, int iPosition, TCHAR* szBuffer)
{
int iLengthMinute, iLengthSecond, iPositionMinute, iPositionSecond;
iLengthMinute = iLength/60;//总时长分钟
iLengthSecond = iLength-iLengthMinute*60;//总时长秒钟
iPositionMinute = iPosition/60;//当前时长分钟
iPositionSecond = iPosition - iPositionMinute*60;//当前时长秒钟
//显示
wsprintf(szBuffer, "%02d:%02d / %02d:%02d", iPositionMinute, iPositionSecond, iLengthMinute, iLengthSecond);
}

//文件夹选择对话框
//参考:http://blog.csdn.net/ShardowM/archive/2008/06/06/2516213.aspx
//http://topic.csdn.net/t/20021103/14/1143060.html
//http://www.programfan.com/blog/article.asp?id=19614
void SelectFolder(HWND hwnd)
{
LPMALLOC lpMalloc = NULL;
if(SUCCEEDED(SHGetMalloc(&lpMalloc)))
{
TCHAR szPath[MAX_PATH];
BROWSEINFO bi;
LPITEMIDLIST pidl;
//LPBYTE pBuf = (LPBYTE)CoTaskMemAlloc(sizeof(bi));
ZeroMemory(&bi, sizeof(bi));//注意结构体的置零
bi.hwndOwner = hwnd;
bi.pidlRoot = NULL;
bi.pszDisplayName = szPath;
bi.lpszTitle = TEXT("选择目录:");
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_BROWSEFORCOMPUTER;
bi.lpfn = NULL;
bi.lParam = 0;
bi.iImage = 0;
if((pidl = SHBrowseForFolder(&bi)) != NULL)//显示文件夹选择对话框并操作
{
SHGetPathFromIDList(pidl, szPath);//转换文件夹路径
FindAllFile(hwnd, szPath, "*.mp3");//查找文件夹下mp3文件
FindAllFile(hwnd, szPath, "*.wma");//wma
FindAllFile(hwnd, szPath, "*.wav");//wav
//MessageBox(NULL, szPath, "", MB_OK);
}
//CoTaskMemFree(pBuf);
lpMalloc->Free(pidl);
lpMalloc->Release();
}
}

//是否是根目录
//根目录路径如:F:\
//非根目录路径如:F:\Music
BOOL IsRoot(LPCTSTR lpszPath)
{
return 3 == lstrlen(lpszPath);
}

//遍历文件夹,找出指定后缀文件。
//参考:http://www.programfan.com/club/showpost.asp?id=18098
//http://hi.baidu.com/csuhkx/blog/item/cb66ff00d82bc610738b6521.html
void FindAllFile(HWND hwnd, LPCTSTR lpszPath, LPCTSTR lpszSuffix)
{
WIN32_FIND_DATA wfd;
TCHAR szPath[MAX_PATH];
lstrcpy(szPath, lpszPath);
if(!IsRoot(szPath))//非根目录加上"\\"
lstrcat(szPath, "\\");
lstrcat(szPath, lpszSuffix);//加上后缀
HANDLE hFind = FindFirstFile(szPath, &wfd);
if(INVALID_HANDLE_VALUE == hFind)//未找到文件,返回。
return;
do
{
if('.' == wfd.cFileName[0])
continue;
if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)//如果是目录,递归进入目录遍历。
{
if(IsRoot(lpszPath))//根目录
wsprintf(szPath, "%s%s", lpszPath, wfd.cFileName);
else//非根目录
wsprintf(szPath, "%s\\%s", lpszPath, wfd.cFileName);
FindAllFile(hwnd, szPath, lpszSuffix);
}
else
{
if(IsRoot(lpszPath))//根目录
wsprintf(szPath, "%s%s", lpszPath, wfd.cFileName);
else//非根目录
wsprintf(szPath, "%s\\%s", lpszPath, wfd.cFileName);
lstrcpy(szFileName[iNum++], szPath);
SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_ADDSTRING, 0, (LPARAM)wfd.cFileName);
//MessageBox(NULL, szPath, "", MB_OK);
}
}while(FindNextFile(hFind, &wfd));
FindClose(hFind);
iPlayListIndex = iNum-1;//加入的最后一个文件
//设置选中项
SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_SETCURSEL, (WPARAM)iPlayListIndex, 0);
//播放选中项
Play(hwnd, iPlayListIndex);
}

MusicPlayer