修增V1.1中已知bug;

自动播放下一首;

最小化到托盘;

自动加载和保存播放列表。

//连接库
//mciSendString winmm.lib
//COM ole32.lib
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>//滚动条控制时包含头文件
#include <objbase.h>//CoInitializeEx包含头文件
#include <shlobj.h>//文件夹选择对话框包含头文件
#include <stdio.h>//文件操作
#include "main.h"
#include "dialogs.h"
#include "resource.h"
#include "rsrc.inc"

#define WM_NOTIFYICON WM_USER+1

TCHAR szFileName[100][MAX_PATH];//播放列表,存储最大值100。
int iNum = 0;//音乐数
int iPlay = 0;//播放状态:0未播放 1正在播放 2暂停
int iTempPlay = 0;//用于IDC_LST1 LBN_SELCHANGE
int iPlayListIndex = 0;//播放列表索引
int iLength;//播放文件时长秒数
NOTIFYICONDATA nid;//托盘图标

BOOL WINAPI Main_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
        //BEGIN MESSAGE CRACK
        //HANDLE_MSG消息分析器参考:http://hi.baidu.com/%C7%C6%C0%B4%C7%C3%C8%A5/blog/item/37a8e43ea710ede554e723b6.html
        HANDLE_MSG(hWnd, WM_INITDIALOG, Main_OnInitDialog);
        HANDLE_MSG(hWnd, WM_COMMAND, Main_OnCommand);
        HANDLE_MSG(hWnd, WM_CLOSE, Main_OnClose);
        HANDLE_MSG(hWnd, WM_HSCROLL, Main_OnHScroll);//水平滚动条消息。WM_VSCROLL垂直滚动条消息。
        HANDLE_MSG(hWnd, WM_SIZE, Main_OnSize);//处理最小化到托盘图标。
  case WM_NOTIFYICON://单击托盘图标恢复界面。
   if(WM_LBUTTONUP == (UINT)lParam)
   {
    Shell_NotifyIcon(NIM_DELETE, &nid);
    ShowWindow(hWnd, SW_NORMAL);
    SetForegroundWindow(hWnd);//激活
    return TRUE;
   }
   return FALSE;
        //END MESSAGE CRACK
    }

    return FALSE;//如果没有对应的消息处理,则返回父窗口FALSE。
}

////////////////////////////////////////////////////////////////////////////////
//  Main_OnInitDialog
BOOL Main_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
    // Set app icons
    //设置图标 ICON_BIG大图标 ICON_SMALL小
    HICON hIcon = LoadIcon((HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), MAKEINTRESOURCE(IDI_ICONAPP));
    SendMessage(hwnd, WM_SETICON, ICON_BIG,  (LPARAM)hIcon);
    SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
   
    //
    // Add initializing code here
    //
    //音量滚动条
    //设置滚动条取值范围
 //参考: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, 800);//当前位置
   if(!Load(hwnd))//加载播放列表
    MessageBox(hwnd, TEXT("MusicPlayer播放列表加载失败"), TEXT("MusicPlayer Error"), MB_OK | MB_ICONERROR);
   
    return TRUE;
}

////////////////////////////////////////////////////////////////////////////////
//  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, TEXT("暂停"));          
   }
   else if(1 == iPlay)//正在播放
   {
    //暂停正在播放文件
      mciSendString("pause OpenMusicFile", (LPTSTR)NULL, 0, NULL);
      //改变播放状态
      iPlay = 2;
      //改变按钮显示文字
      SetWindowText(hwndCtl, TEXT("播放"));  
   }
   else//暂停
   {
    //恢复暂停播放文件
    mciSendString("play OpenMusicFile", (LPTSTR)NULL, 0, NULL);
    //改变播放状态
     iPlay = 1;
     //改变按钮显示文字
      SetWindowText(hwndCtl, TEXT("暂停"));
   }
   break;
  case IDC_BTNPREV://上一首
   //播放或暂停时,取消原来因为调用Play函数时设置的定时器。
   if(iPlay)
    KillTimer(hwnd, 1);
   //获得上一首播放列表索引
   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), TEXT("暂停"));
   }
   else
    iPlayListIndex = 0;
  break;
  case IDC_BTNNEXT://下一首
   if(iPlay)
    KillTimer(hwnd, 1); 
   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), TEXT("暂停"));
   }
   else
    iPlayListIndex = iNum - 1;
  break;
        case IDC_LST1://列表消息
         switch(codeNotify)
         {
          case LBN_SELCHANGE://选中项改变
           //获得选中项播放列表索引
           int iChange = SendMessage(hwndCtl, LB_GETCURSEL, 0, 0);
           if(iChange != iPlayListIndex)//索引改变
           {
            if(iPlay)
       iTempPlay = iPlay;//保存文件播放状态
       iPlay = 0;//新文件未播放
        SetWindowText(GetDlgItem(hwnd, IDC_BTNPLAY), TEXT("播放"));
           }
           else//索引未改变
           {
            iPlay = iTempPlay;//恢复文件播放状态
      if(1 == iPlay)
             SetWindowText(GetDlgItem(hwnd, IDC_BTNPLAY), TEXT("暂停"));
       else
        SetWindowText(GetDlgItem(hwnd, IDC_BTNPLAY), TEXT("播放"));
           }
     break;     
          case LBN_DBLCLK://双击某项
     //播放或暂停时,取消原来因为调用Play函数时设置的定时器。
     if(iPlay)
      KillTimer(hwnd, 1);
           iPlayListIndex = SendMessage(hwndCtl, LB_GETCURSEL, 0, 0);
           Play(hwnd, iPlayListIndex);
       SetWindowText(GetDlgItem(hwnd, IDC_BTNPLAY), TEXT("暂停"));
           break;
          default:break;
   }
  break;
  case IDC_BTNMOVEUP:
   int iTempPlayListIndex = SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_GETCURSEL, 0, 0);//选中项索引
   if(iTempPlayListIndex > 0)//选中项索引大于0才能上移
   {
    TCHAR szTempFileName[MAX_PATH];//存放选中文件路径临时变量
    if(iTempPlayListIndex != iPlayListIndex)
    {    
     //上移
     lstrcpy(szTempFileName, szFileName[iTempPlayListIndex]);
     lstrcpy(szFileName[iTempPlayListIndex], szFileName[iTempPlayListIndex-1]);
     lstrcpy(szFileName[--iTempPlayListIndex], szTempFileName);
     //通过文件路径获取文件名
     TCHAR* p = strrchr(szFileName[iTempPlayListIndex], '\\');
     p++;
     SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_INSERTSTRING, iTempPlayListIndex, (LPARAM)p);//在新位置插入文件名
     SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_DELETESTRING, iTempPlayListIndex+2, 0);//删除原位置文件名
     SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_SETCURSEL, iTempPlayListIndex, 0);//设置选中项
    }
    else
    {
     //上移
     lstrcpy(szTempFileName, szFileName[iPlayListIndex]);
     lstrcpy(szFileName[iPlayListIndex], szFileName[iPlayListIndex-1]);
     lstrcpy(szFileName[--iPlayListIndex], szTempFileName);
     //通过文件路径获取文件名
     TCHAR* p = strrchr(szFileName[iPlayListIndex], '\\');
     p++;
     SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_INSERTSTRING, iPlayListIndex, (LPARAM)p);//在新位置插入文件名
     SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_DELETESTRING, iPlayListIndex+2, 0);//删除原位置文件名
     SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_SETCURSEL, iPlayListIndex, 0);//设置选中项
    }
   }
  break;
  case IDC_BTNMOVEDOWN:
   iTempPlayListIndex = SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_GETCURSEL, 0, 0);//选中项索引
   if(iTempPlayListIndex < iNum-1)//选中项索引小于iNum-1才能下移
   {
    TCHAR szTempFileName[MAX_PATH];//存放选中文件路径临时变量
    if(iTempPlayListIndex != iPlayListIndex)
    {
     //下移
     lstrcpy(szTempFileName, szFileName[iTempPlayListIndex]);
     lstrcpy(szFileName[iTempPlayListIndex], szFileName[iTempPlayListIndex+1]);
     lstrcpy(szFileName[++iTempPlayListIndex], szTempFileName);
     //通过文件路径获取文件名
     TCHAR* p = strrchr(szFileName[iTempPlayListIndex], '\\');
     p++;
     SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_INSERTSTRING, iTempPlayListIndex+1, (LPARAM)p);//在新位置插入文件名
     SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_DELETESTRING, iTempPlayListIndex-1, 0);//删除原位置文件名
     SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_SETCURSEL, iTempPlayListIndex, 0);//设置选中项
    }
    else
    {
     //下移
     lstrcpy(szTempFileName, szFileName[iPlayListIndex]);
     lstrcpy(szFileName[iPlayListIndex], szFileName[iPlayListIndex+1]);
     lstrcpy(szFileName[++iPlayListIndex], szTempFileName);
     //通过文件路径获取文件名
     TCHAR* p = strrchr(szFileName[iPlayListIndex], '\\');
     p++;
     SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_INSERTSTRING, iPlayListIndex+1, (LPARAM)p);//在新位置插入文件名
     SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_DELETESTRING, iPlayListIndex-1, 0);//删除原位置文件名
     SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_SETCURSEL, iPlayListIndex, 0);//设置选中项
    }
   }
  break;
  case IDC_BTNDELETE:
   if(0 == iNum)
    break;//没有文件时,不执行删除操作。
   iTempPlayListIndex = SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_GETCURSEL, 0, 0);//选中项索引
   if(iTempPlayListIndex == iPlayListIndex)//选中项是播放文件
   {
    //播放或暂停状态,关闭文件,取消定时器,设置播放状态。
    if(iPlay)
    {
     mciSendString("close OpenMusicFile", (LPTSTR)NULL, 0, 0);
     KillTimer(hwnd, 1);
     iPlay = 0;
    }
    if(iPlayListIndex == iNum-1)//如果是最后一首,则iPlayListIndex指向删除后的最后一首。    
     iPlayListIndex--;
   }
   else//选中项不是播放文件,则参看IDC_LST1 LBN_SELCHANGE。
   {
    iPlay = 1;
   }
   if(iTempPlayListIndex < iPlayListIndex)//选中项在iPlayListIndex前,则iPlayListIndex指向删除后的正在播放文件。
    iPlayListIndex--;
   //处理播放文件列表
   for(int i = iTempPlayListIndex; i < iNum-1; i++)
   {
    lstrcpy(szFileName[i], szFileName[i+1]);
   }
   szFileName[--iNum][0] = '\0';//删除项内容清空
   //处理IDC_LST1
   SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_DELETESTRING, iTempPlayListIndex, 0);
   if(iTempPlayListIndex == iNum)
    iTempPlayListIndex--;
   SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_SETCURSEL, iTempPlayListIndex, 0);
   if(0 == iPlay)
    Play(hwnd, iPlayListIndex);
  break;
        default:break;
    }
}

////////////////////////////////////////////////////////////////////////////////
//  Main_OnClose
void Main_OnClose(HWND hwnd)
{
 if(!Save())//保存播放列表
  MessageBox(hwnd, TEXT("MusicPlayer播放列表保存失败"), TEXT("MusicPlayer Error"), MB_OK | MB_ICONERROR);
    EndDialog(hwnd, 0);
}

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

void Main_OnSize(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 if(SIZE_MINIMIZED == message)//最小化消息在WM_SIZE消息的wParam参数里
 {
  ZeroMemory(&nid, sizeof(nid));
  nid.cbSize = sizeof(nid);
  nid.hWnd = hwnd;
  nid.uID = IDI_ICONAPP;
  nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  nid.uCallbackMessage = WM_NOTIFYICON;
  nid.hIcon = LoadIcon((HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), MAKEINTRESOURCE(IDI_ICONAPP));
  lstrcpy(nid.szTip, "MusicPlayer");
  Shell_NotifyIcon(NIM_ADD, &nid);
  ShowWindow(hwnd, SW_HIDE);
 }
}

void OpenFiles(HWND hwnd)
{
 //定时器设置参考文件夹选择对话框
 if(iPlay)
  KillTimer(hwnd, 1);
 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)
    {
    if(iNum >= 100)
    {
    MessageBox(hwnd, TEXT("MusicPlayer已达到最大音乐数100"), TEXT("MusicPlayer Error"), MB_OK | MB_ICONERROR);
     return;
    }  
      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); 
 }
 else
 {
  if(iPlay)
   SetTimer(hwnd, 1, 1000, PlayProcess);
 }
}

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));
 //转成短路径失败
  DWORD dwError = GetLastError();
 //如果操作失败
   if(0 != dwError)
   {
      LPVOID lpMsgBuf = NULL;
  //将dwError错误代码转化为字符串lpMsgBuf
      FormatMessage(
       FORMAT_MESSAGE_ALLOCATE_BUFFER |
       FORMAT_MESSAGE_FROM_SYSTEM,
       NULL,
       dwError,
       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
       (LPTSTR)&lpMsgBuf,
       0, NULL );
     //显示错误原因
     MessageBox(NULL, (LPTSTR)lpMsgBuf, "Error", MB_OK|MB_ICONSTOP);    
     //释放Buffer
     LocalFree(lpMsgBuf);
     return;
  }
 //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(iPosition, szBuffer);
 //SetWindowText(GetDlgItem(hwnd, IDC_STCTIME), szBuffer);
 ShowTime(hwnd, iPosition);
 SendMessage(GetDlgItem(hwnd, IDC_TRBPROCESS), TBM_SETPOS, TRUE, (LPARAM)iPosition);//设置进度滚动条位置
 if(iPosition == iLength)//结束
 {  
  mciSendString("close OpenMusicFile", (LPTSTR)NULL, 0, 0);
  iPlay = 0;
  KillTimer(hwnd, 1);
  SetWindowText(GetDlgItem(hwnd, IDC_STCTIME), TEXT("00:00 / 00:00"));
  SendMessage(GetDlgItem(hwnd, IDC_TRBPROCESS), TBM_SETPOS, TRUE, 0);
  SetWindowText(GetDlgItem(hwnd, IDC_BTNPLAY), TEXT("播放"));
  if(iPlayListIndex < iNum)
   SendMessage(hwnd, WM_COMMAND, IDC_BTNNEXT, 0);
 }
}

void FormatTime(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);
}

void ShowTime(HWND hwnd, int iPosition)
{
 TCHAR szBuffer[20];
 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);
 SetWindowText(GetDlgItem(hwnd, IDC_STCTIME), szBuffer);
}

//文件夹选择对话框
//参考: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)
{
 if(iPlay)
  KillTimer(hwnd, 1);//定时器影响文件夹选择对话框,故取消。
 LPMALLOC lpMalloc = NULL;
 if(SUCCEEDED(SHGetMalloc(&lpMalloc)))
 {
  TCHAR szPath[MAX_PATH];
  BROWSEINFO bi;
  LPITEMIDLIST pidl = NULL;
  ZeroMemory(szPath, sizeof(szPath));//注意结构体的置零
  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;
  CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);//初始化COM库
  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(pidl);
  }
  else
  {
   if(iPlay)
    SetTimer(hwnd, 1, 1000, PlayProcess);//按取消,恢复定时器。
  }
  //lpMalloc->Free(pidl);
  lpMalloc->Release();
  CoUninitialize();//关闭COM库  
 }
}

//是否是根目录
//根目录路径如: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);
    if(iNum >= 100)
    {
     MessageBox(hwnd, TEXT("MusicPlayer已达到最大音乐数100"), TEXT("MusicPlayer Error"), MB_OK | MB_ICONERROR);
     return;
    }
     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); 
}

BOOL Save()
{
 /*头文件#include <dir.h>
  TCHAR szBuffer[MAX_PATH];
   TCHAR szPath[MAX_PATH];
   TCHAR szListPath[MAX_PATH];
   getcwd(szBuffer, MAX_PATH);//取得当前工作目录
   GetShortPathName(szBuffer, szPath, MAX_PATH);
   wsprintf(szListPath, "%s\\%s", szPath, "MusicPlayer.list");
   */
   //以二进制形式、分块存储播放列表
  FILE* fp;
 if((fp=fopen("C:\\MusicPlayer.list", "wb")) == NULL)
  return false;
 for(int i = 0; i < iNum; i++)
 {
  fwrite(&szFileName[i], sizeof(TCHAR)*MAX_PATH, 1, fp);//分块存储
 }
 fclose(fp);
 return true;
}

BOOL Load(HWND hwnd)
{
 //以二进制形式读取播放列表
 FILE* fp;
 if((fp=fopen("C:\\MusicPlayer.list", "rb")) == NULL)
  return false;
 fseek(fp, 0, 2);//移动指针到文件尾
   int n = ftell(fp);//检测当前指针位置,得到文件长度。
 rewind(fp);//将指针复位到文件头
 if(0 == n)
  return true;
 n = n/(sizeof(TCHAR)*MAX_PATH);
 while(n--)
 { 
  PSTR pszFileName = NULL;//文件名起始地址
  fread(szFileName[iNum], sizeof(TCHAR)*MAX_PATH, 1, fp);//分块读取
  pszFileName = strrchr(szFileName[iNum++], '\\');//返回szFileName[iNum++]里'\\'最后出现的位置
  if(pszFileName++)//如果有'\\'则pszFileName++为文件名起始地址
  {
   SendMessage(GetDlgItem(hwnd, IDC_LST1), LB_ADDSTRING, 0, (LPARAM)pszFileName);//添加到ListBox里
  }
 }
 fclose(fp);
 if(iNum)//如果有音乐则播放第一首。
  SendMessage(hwnd, WM_COMMAND, IDC_BTNNEXT, 0);
 return true;
}

MusicPlayer V1.2