[更新]基于MFC对话框并使用MCI接口的音乐播放器

使用MCI接口编写能播放MP3,WAV格式的音频文件

程序信息:
程序名称:My Music Player
作者 :CodeMore
编译时间:2016年1月31日 星期日
版本: 1.0
程序原理:使用Windows中的MCI接口
编译环境: Win 10 64位专业版 和VC2010旗舰版
本播放器有以下特点:
1.程序能播放MP3, WAV格式的音频文件,采用Windows系统的MCI(媒体控制接口)进行播放。
2.播放MP3音频文件时,能够在歌曲信息区域显示文件的tag信息(歌手,专辑,发行年份等)。采用id3lib库进行开发获取,详细见源码。
3.播放器支持4种播放模式(顺序播放、单曲循环、单曲播放、随机播放)。
4.播放列表控件支持双击播放操作,支持单击项目显示歌曲信息等功能。
5.在Win7和10 平台上支持任务栏上显示音频播放进度,xp平台未测试。
致谢:
MP3FileInfo类来源于CodeProject网上的大神(Christian Richardt)。

程序界面:
主程序界面

程序的各个控件ID值:
控件ID

程序代码:
**1.标准应用程序框架
stdafx.h**


// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件

#pragma once

#ifndef _SECURE_ATL
#define _SECURE_ATL 1
#endif

#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN            // 从 Windows 头中排除极少使用的资料
#endif

#include "targetver.h"


#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS      // 某些 CString 构造函数将是显式的

// 关闭 MFC 对某些常见但经常可放心忽略的警告消息的隐藏
#define _AFX_ALL_WARNINGS

#include <afxwin.h>         // MFC 核心组件和标准组件
#include <afxext.h>         // MFC 扩展

#ifndef _AFX_NO_OLE_SUPPORT
#include <afxdtctl.h>           // MFCInternet Explorer 4 公共控件的支持
#endif
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>             // MFCWindows 公共控件的支持
#endif // _AFX_NO_AFXCMN_SUPPORT

#include <afxcontrolbars.h>     // 功能区和控件条的 MFC 支持


#include <MMSystem.h>       //MCI支持的头文件
#include <Digitalv.h>
#pragma comment (lib,"winmm.lib")

// MP3FileInfo 
#include <assert.h>
#include <stdio.h>
#include "MP3FileInfo.h"


//支持windows 7的visual style
//Unicode版本
#ifdef _UNICODE
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#endif
//多字节版本
#ifdef _MBCS
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#endif

stdafx的实现文件:


// stdafx.cpp : 只包括标准包含文件的源文件
// My Music Player.pch 将作为预编译头
// stdafx.obj 将包含预编译类型信息

#include "stdafx.h"

NiceSlider头文件(主要是用于滑块的精确移动)

/****************
*类名:CNiceSliderCtrl
*功能:支持滑块滑动功能,做到精确无误。
*/

#ifndef NiceSlider_h
#define NiceSlider_h

// Class that provides better mouse click handling for the standard windows slider control
class CNiceSliderCtrl : public CSliderCtrl
{
public:
    DECLARE_DYNAMIC(CNiceSliderCtrl)
        CNiceSliderCtrl() : m_bDragging(false), m_bDragChanged(false) {}
protected:
    //{{AFX_MSG(CRoundSliderCtrl)
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
private:
    bool SetThumb(const CPoint& pt);
    void PostMessageToParent(const int nTBCode) const;
    bool m_bDragging;
    bool m_bDragChanged;
};
#endif // NiceSlider_h

NiceSlider的实现文件

/****************
*类名:CNiceSliderCtrl
*功能:实现文件
*文件名:NiceSlider.cpp
*/
#include "stdafx.h"
#include "NiceSlider.h"

IMPLEMENT_DYNAMIC(CNiceSliderCtrl, CSliderCtrl)


BEGIN_MESSAGE_MAP(CNiceSliderCtrl, CSliderCtrl)
    //{{AFX_MSG_MAP(CNiceSliderCtrl)
    ON_WM_LBUTTONDOWN()
    ON_WM_MOUSEMOVE()
    ON_WM_LBUTTONUP()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()


void CNiceSliderCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
    m_bDragging = true;
    m_bDragChanged = false;
    SetCapture();
    SetFocus();
    if (SetThumb(point))
    {
        m_bDragChanged = true;
        PostMessageToParent(TB_THUMBTRACK);
    }
}


void CNiceSliderCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
    if (m_bDragging)
    {
        if (SetThumb(point))
        {
            m_bDragChanged = true;
            PostMessageToParent(TB_THUMBTRACK);
        }
    }
    else
    {
        CSliderCtrl::OnMouseMove(nFlags, point);
    }
}

void CNiceSliderCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
{
    if(m_bDragging)
    {
        m_bDragging = false;
        ::ReleaseCapture();
        if (SetThumb(point))
        {
            PostMessageToParent(TB_THUMBTRACK);
            m_bDragChanged = true;
        }
        if (m_bDragChanged)
        {
            PostMessageToParent(TB_THUMBPOSITION);
            m_bDragChanged = false;
        }
    }
    else
    {
        CSliderCtrl::OnLButtonUp(nFlags, point);
    }
}


bool CNiceSliderCtrl::SetThumb(const CPoint& point)
{
    const int nMin = GetRangeMin();
    const int nMax = GetRangeMax()+1;
    CRect rc;
    GetChannelRect(rc);
    double dPos;
    double dCorrectionFactor = 0.0;
    if (GetStyle() & TBS_VERT) 
    {
        // note: there is a bug in GetChannelRect, it gets the orientation of the rectangle mixed up
        dPos = (double)(point.y - rc.left)/(rc.right - rc.left);
    }
    else
    {
        dPos = (double)(point.x - rc.left)/(rc.right - rc.left);
    }
    // This correction factor is needed when you click inbetween tick marks
    // so that the thumb will move to the nearest one
    dCorrectionFactor = 0.5 *(1-dPos) - 0.5 *dPos;
    int nNewPos = (int)(nMin + (nMax-nMin)*dPos + dCorrectionFactor);
    const bool bChanged = (nNewPos != GetPos());
    if(bChanged)
    {
        SetPos(nNewPos);
    }
    return bChanged;
}

void CNiceSliderCtrl::PostMessageToParent(const int nTBCode) const
{
    CWnd* pWnd = GetParent();
    if(pWnd) pWnd->PostMessage(WM_HSCROLL, (WPARAM)((GetPos() << 16) | nTBCode), (LPARAM)GetSafeHwnd());
}

**MP3FileInfo头文件
主要用于获取Mp3的tag信息**

/*

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                        MP3FileInfo 1.0
                    -----------------------

  MP3FileInfo is a wrapper class for id3lib, a library capable
  of reading and writing ID3 Tags of MP3 Files. It has a
  simple interface and provides all data as public members.

  Written by Christian Richardt (cr@whizer.net).

  Release history:
    Mai 31, 2003: Version 1.0. First release.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

*/

/**
  \file    MP3FileInfo.h
  \brief   Reads Header and ID3 Tags of MP3 Files
  \date    2003-05-31
  \author  Christian Richardt (cr@whizer.net)
**/

#ifndef MP3FILEINFO_H
#define MP3FILEINFO_H


/* ---- use id3lib ---- */

    // "If you use id3lib.dll (you link dynamic) you should add
    //  ID3LIB_LINKOPTION=3 to your preprocessor definitions of your project."
  #define ID3LIB_LINKOPTION 3
  #include <id3/tag.h>
  #pragma comment(lib, "id3lib.lib")


    /**
      \brief   Reads Header and ID3 Tags of MP3 Files

      MP3FileInfo is a wrapper class for id3lib, a library capable
      of reading and writing ID3 Tags of MP3 Files. It has a
      simple interface and provides all data as public members.

      How to use MP3FileInfo:

      \code
        MP3FileInfo obj; // don't use at this point!

        if(!obj.Init("some-file.mp3"))
         { ... error ... }

        ... use MP3FileInfo ...
      \end

      The object frees all allocated memory if deleted. Always
      Initalize this class by calling Init(). It returns false if
      an error occured. You can call Init() as often as you want.
      All data is being freed before the data of the new file is
      extracted.

      Always call isOK() to check whether the class is all right!
    **/
  class MP3FileInfo
   {
    public:
      inline MP3FileInfo(void) :
        m_bOK(true),
        m_id3tag(0),
        m_mp3header(0),

          // Fileinfo
        szFilename(0), nFileSize(-1),
        bHasLyrics(false), bHasV1Tag(false), bHasV2Tag(false),

          // Headerinfo
        nBitRate(0), nCbrBitRate(0), nVbrBitRate(0), nSampleRate(0), nLength(0),
        szBitRate(0), szMpegLayer(0), szMpegVersion(0), szChannelMode(0),

          // ID3V1 Tag elements
        szArtist(0), szAlbum(0), szGenre(0), szTitle(0), szYear(0), szComment(0), szTrack(0),

          // ID3V2 Tag elements
        szComposer(0), szCopyright(0), szEncodedBy(0), szOriginalArtist(0), szURL(0)
       {
        // nothing to do; use Init() instead
       }

      virtual ~MP3FileInfo(void) { Free(); }


      bool Init(const char* cszFilename);
      void Free(void);
      inline bool isOK(void) const { return m_bOK; }


      /* Fileinfo */
      char* szFilename;
      bool  bHasLyrics, bHasV1Tag, bHasV2Tag;
      int   nFileSize;

      /* Headerinfo */
      int nCbrBitRate, nVbrBitRate, nBitRate, nSampleRate, nLength;
      char* szBitRate;
      char* szMpegLayer;
      char* szMpegVersion;
      char* szChannelMode;

      /* V1 up */
      char* szArtist;
      char* szTitle;
      char* szAlbum;
      char* szComment;
      char* szTrack; int nTrack;
      char* szYear; int nYear;
      char* szGenre;

      /* V2 only */
      char* szComposer;
      char* szCopyright;
      char* szEncodedBy;
      char* szOriginalArtist;
      char* szURL;

      void  ShowAllFrames(void);


    protected:
      bool m_bOK;

      ID3_Tag* m_id3tag;
      const Mp3_Headerinfo* m_mp3header;

      void m_parseFile(void);
      void m_parseHeader(void);
      void m_parseGenre(void);

      bool  m_getString(ID3_FrameID fid, char* szBuffer);
      char* m_getNewString(ID3_FrameID fid);
   };
#endif // MP3FILEINFO_H

MP3FileInfo的实现文件

/*

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                        MP3FileInfo 1.0
                    -----------------------

  MP3FileInfo is a wrapper class for id3lib, a library capable
  of reading and writing ID3 Tags of MP3 Files. It has a
  simple interface and provides all data as public members.

  Written by Christian Richardt (cr@whizer.net).

  Release history:
    Mai 31, 2003: Version 1.0. First release.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

*/

/**
  \file    MP3FileInfo.cpp
  \brief   Reads Header and ID3 Tags of MP3 Files
  \date    2003-05-31
  \author  Christian Richardt (cr@whizer.net)
**/


  #include "stdafx.h"
  #include <assert.h>
  #include <stdio.h>



/* ----------------------- Init and Free ------------------------ */


    /**
      \brief   Initialize and parse all data

      Always Initalize this class by calling Init(). It returns
      false if an error occured.

      You can call Init() as often as you want. All data is being
      freed before extracting the data of the new file.
    **/
  bool MP3FileInfo::Init(const char* cszFilename)
   {
    Free();
    m_bOK = true;

      // copy filename
    szFilename = new char[strlen(cszFilename)+1];

    strcpy_s(szFilename, strlen(cszFilename)+1, cszFilename);

    m_id3tag = new ID3_Tag;
    m_id3tag->Link(szFilename);

    /* Fileinfo */
    bHasLyrics = m_id3tag->HasLyrics();
    bHasV1Tag  = m_id3tag->HasV1Tag();
    bHasV2Tag  = m_id3tag->HasV2Tag();
    nFileSize  = (int)m_id3tag->GetFileSize();

    /* Headerinfo */
    m_parseHeader();
    if(!m_bOK) { Free(); return m_bOK; }

    /* V1 up */
    szAlbum   = m_getNewString(ID3FID_ALBUM);
    szArtist  = m_getNewString(ID3FID_LEADARTIST);
    szComment = m_getNewString(ID3FID_COMMENT);
    szTitle   = m_getNewString(ID3FID_TITLE);
    szTrack   = m_getNewString(ID3FID_TRACKNUM);
    szYear    = m_getNewString(ID3FID_YEAR);

    /* V2 */
    szComposer        = m_getNewString(ID3FID_COMPOSER);
    szCopyright       = m_getNewString(ID3FID_COPYRIGHT);
    szEncodedBy       = m_getNewString(ID3FID_ENCODEDBY);
    szOriginalArtist  = m_getNewString(ID3FID_ORIGARTIST);
    szURL             = m_getNewString(ID3FID_WWWUSER);

    m_parseGenre();
    if(szYear)  sscanf_s(szYear,  "%i", &nYear);
    if(szTrack) sscanf_s(szTrack, "%i", &nTrack);

    return m_bOK;
   }


    /**
      \brief   Free all allocated ressources

      You can call Free() as often as you want.
      No error is raised.
    **/
  void MP3FileInfo::Free(void)
   {
    if(m_bOK) // only free if OK
     {
      m_bOK = false;

      if(m_id3tag!=0)
       {
          // in rare cases (e.g. if file is corrupt)
          // "delete m_id3tag" fails ...
        try { delete m_id3tag; } catch(...) {}
        m_id3tag = 0;
       }

      /* fileinfo */
      delete[] szFilename; szFilename = 0; nFileSize = -1;
      bHasLyrics = false; bHasV1Tag = false; bHasV2Tag = false;

      /* headerinfo */
      m_mp3header = 0;
      nVbrBitRate = 0; nBitRate = 0; nCbrBitRate = 0;
      nSampleRate = 0; nLength  = 0;
      delete[] szBitRate;     szBitRate = 0;
      delete[] szMpegLayer;   szMpegLayer = 0;
      delete[] szMpegVersion; szMpegVersion = 0;
      delete[] szChannelMode; szChannelMode = 0;

      /* ID3V1 Tag elements */
      nTrack = 0; nYear = 0;
      delete[] szArtist;  szArtist  = 0;
      delete[] szTitle;   szTitle   = 0;
      delete[] szAlbum;   szAlbum   = 0;
      delete[] szComment; szComment = 0;
      delete[] szTrack;   szTrack   = 0;
      delete[] szYear;    szYear    = 0;
      delete[] szGenre;   szGenre   = 0;

      /* V2 up */
      delete[] szComposer;        szComposer= 0;
      delete[] szCopyright;       szCopyright= 0;
      delete[] szEncodedBy;       szEncodedBy= 0;
      delete[] szOriginalArtist;  szOriginalArtist= 0;
      delete[] szURL;             szURL= 0;
     }
   }


/* ---------------- public member functions ---------------- */


    /// prints all frames the file contains
  void MP3FileInfo::ShowAllFrames(void)
   {
    assert(m_bOK);

      // all FrameIDs
    ID3_FrameID fids[] = { ID3FID_NOFRAME,          ID3FID_AUDIOCRYPTO,     ID3FID_PICTURE,             ID3FID_AUDIOSEEKPOINT,  ID3FID_COMMENT,
                           ID3FID_COMMERCIAL,       ID3FID_CRYPTOREG,       ID3FID_EQUALIZATION2,       ID3FID_EQUALIZATION,    ID3FID_EVENTTIMING,
                           ID3FID_GENERALOBJECT,    ID3FID_GROUPINGREG,     ID3FID_INVOLVEDPEOPLE,      ID3FID_LINKEDINFO,      ID3FID_CDID,
                           ID3FID_MPEGLOOKUP,       ID3FID_OWNERSHIP,       ID3FID_PRIVATE,             ID3FID_PLAYCOUNTER,     ID3FID_POPULARIMETER,
                           ID3FID_POSITIONSYNC,     ID3FID_BUFFERSIZE,      ID3FID_VOLUMEADJ2,          ID3FID_VOLUMEADJ,       ID3FID_REVERB,
                           ID3FID_SEEKFRAME,        ID3FID_SIGNATURE,       ID3FID_SYNCEDLYRICS,        ID3FID_SYNCEDTEMPO,     ID3FID_ALBUM,
                           ID3FID_BPM,              ID3FID_COMPOSER,        ID3FID_CONTENTTYPE,         ID3FID_COPYRIGHT,       ID3FID_DATE,
                           ID3FID_ENCODINGTIME,     ID3FID_PLAYLISTDELAY,   ID3FID_ORIGRELEASETIME,     ID3FID_RECORDINGTIME,   ID3FID_RELEASETIME,
                           ID3FID_TAGGINGTIME,      ID3FID_INVOLVEDPEOPLE2, ID3FID_ENCODEDBY,           ID3FID_LYRICIST,        ID3FID_FILETYPE,
                           ID3FID_TIME,             ID3FID_CONTENTGROUP,    ID3FID_TITLE,               ID3FID_SUBTITLE,        ID3FID_INITIALKEY,
                           ID3FID_LANGUAGE,         ID3FID_SONGLEN,         ID3FID_MUSICIANCREDITLIST,  ID3FID_MEDIATYPE,       ID3FID_MOOD,
                           ID3FID_ORIGALBUM,        ID3FID_ORIGFILENAME,    ID3FID_ORIGLYRICIST,        ID3FID_ORIGARTIST,      ID3FID_ORIGYEAR,
                           ID3FID_FILEOWNER,        ID3FID_LEADARTIST,      ID3FID_BAND,                ID3FID_CONDUCTOR,       ID3FID_MIXARTIST,
                           ID3FID_PARTINSET,        ID3FID_PRODUCEDNOTICE,  ID3FID_PUBLISHER,           ID3FID_TRACKNUM,        ID3FID_RECORDINGDATES,
                           ID3FID_NETRADIOSTATION,  ID3FID_NETRADIOOWNER,   ID3FID_SIZE,                ID3FID_ALBUMSORTORDER,  ID3FID_PERFORMERSORTORDER,
                           ID3FID_TITLESORTORDER,   ID3FID_ISRC,            ID3FID_ENCODERSETTINGS,     ID3FID_SETSUBTITLE,     ID3FID_USERTEXT,
                           ID3FID_YEAR,             ID3FID_UNIQUEFILEID,    ID3FID_TERMSOFUSE,          ID3FID_UNSYNCEDLYRICS,  ID3FID_WWWCOMMERCIALINFO,
                           ID3FID_WWWCOPYRIGHT,     ID3FID_WWWAUDIOFILE,    ID3FID_WWWARTIST,           ID3FID_WWWAUDIOSOURCE,  ID3FID_WWWRADIOPAGE,
                           ID3FID_WWWPAYMENT,       ID3FID_WWWPUBLISHER,    ID3FID_WWWUSER,             ID3FID_METACRYPTO,      ID3FID_METACOMPRESSION,
                           ID3FID_LASTFRAMEID
                         };

      // a frame usually contains one field of the following fields:
    ID3_FieldID fiids[] = { ID3FN_NOFIELD, ID3FN_TEXTENC, ID3FN_TEXT, ID3FN_URL, ID3FN_DATA, ID3FN_DESCRIPTION, ID3FN_OWNER, ID3FN_EMAIL, ID3FN_RATING, ID3FN_FILENAME, ID3FN_LANGUAGE, ID3FN_PICTURETYPE, ID3FN_IMAGEFORMAT, ID3FN_MIMETYPE, ID3FN_COUNTER, ID3FN_ID, ID3FN_VOLUMEADJ, ID3FN_NUMBITS, ID3FN_VOLCHGRIGHT, ID3FN_VOLCHGLEFT, ID3FN_PEAKVOLRIGHT, ID3FN_PEAKVOLLEFT, ID3FN_TIMESTAMPFORMAT, ID3FN_CONTENTTYPE, ID3FN_LASTFIELDID};
    char*       idesc[] = { "No field.", "Text encoding (unicode or ASCII).", "Text field.", "A URL.", "Data field.", "Description field.", "Owner field.", "Email field.", "Rating field.", "Filename field.", "Language field.", "Picture type field.", "Image format field.", "Mimetype field.", "Counter field.", "Identifier/Symbol field.", "Volume adjustment field.", "Number of bits field.", "Volume chage on the right channel.", "Volume chage on the left channel.", "Peak volume on the right channel.", "Peak volume on the left channel.", "SYLT Timestamp Format.", "SYLT content type.", "Last field placeholder."};


    int i=0;
    char* buf = 0;
    ID3_Frame* frame = 0;
    ID3_Field* field = 0;
    while(i<96)
     {
      if(i==2 || i==10) // picture and encapsulated object often fail
       {
        printf("%2i. Skipping\n", i);
        i++; continue;
       }

      try { frame = m_id3tag->Find(fids[i]); }
      catch(...)
       {
        printf("ERROR: SKIPPING FILE (i=%i)\n", i);
        Free();
        return;
       }

      if(frame==0) { i++; continue; } // Frame not found
      printf("%2i. %-35s : ", i, frame->GetDescription());

      buf = m_getNewString(fids[i]);
      if(buf)
       {
        printf("\"%s\"\n", buf);
        delete[] buf;
        frame = 0;
        i++; continue;
       }

      printf("No Text found, but:\n", buf);

      for(int k=1; k<24; k++)
       {
        try
         {
          if(frame->Contains(fiids[k]))
           { printf("%-43s- %s\n", "", idesc[k]); }
         }
        catch(...)
         {
          printf("%-42sERROR: SKIPPING FILE (i=%i; k=%i)\n", "", i, k);
          Free();
          return;
         }
       }
      printf("\n");
      frame = 0;
      i++; continue;
     }
    printf("\n");
   }



/* ---------------- protected member functions ---------------- */

    /**
      \brief   parses the genre of the file

      In ID3V1 Tags, the genre is a simple byte and needs to be
      converted to a string first, but ID3V2 allows arbitrary
      genre descriptions.
    **/
  void MP3FileInfo::m_parseGenre(void)
   {
    if(bHasV2Tag) // Use V2 if present
     {
      szGenre = m_getNewString(ID3FID_CONTENTTYPE);
      return;
     }

    char buf[10];
    if(!m_getString(ID3FID_CONTENTTYPE, buf))
     {
      szGenre = 0;
      return;
     }

    int gid;
    sscanf_s(buf, "(%i)", &gid); // filter Genre ID

    if(gid >= ID3_NR_OF_V1_GENRES) // genre ID too large
     {
      szGenre = new char[strlen(buf)+1];

      strcpy_s(szGenre,strlen(buf)+1, buf);

      return;
     }

    szGenre = new char[strlen(ID3_V1GENRE2DESCRIPTION(gid))+1];

    strcpy_s(szGenre, strlen(ID3_V1GENRE2DESCRIPTION(gid))+1, ID3_V1GENRE2DESCRIPTION(gid));
   }

    /// parses header infomation
  void MP3FileInfo::m_parseHeader(void)
   {
    assert(m_bOK);

    m_mp3header = m_id3tag->GetMp3HeaderInfo();
    if(!m_mp3header)
     {
      //printf("\n[Error]:\nGetMp3HeaderInfo() failed!\n(file: %s)\n\n", szFilename);
      Free();
      return;
     }

    nCbrBitRate = m_mp3header->bitrate;
    nVbrBitRate = m_mp3header->vbr_bitrate;
    nSampleRate = m_mp3header->frequency;
    nLength     = m_mp3header->time;

    szBitRate = new char[20];
    if(nVbrBitRate>0)
     {
      sprintf_s(szBitRate, 20,  "%i kbit/s (VBR)", nVbrBitRate/1000);
      nBitRate = nVbrBitRate;
     }
    else
     {
      sprintf_s(szBitRate, 20, "%i kbit/s", nCbrBitRate/1000);
      nBitRate = nCbrBitRate;
     }


      // MPEG Layer
    szMpegLayer = new char[10];
    switch(m_mp3header->layer)
     {
      case MPEGLAYER_UNDEFINED: strcpy_s(szMpegLayer,strlen("UNDEFINED")+1, "UNDEFINED"); break;
      case MPEGLAYER_III:       strcpy_s(szMpegLayer, strlen("Layer III")+1,"Layer III"); break;
      case MPEGLAYER_II:        strcpy_s(szMpegLayer, strlen("Layer II")+1,"Layer II");  break;
      case MPEGLAYER_I:         strcpy_s(szMpegLayer, strlen("Layer I")+1,"Layer I");   break;
      default:                  szMpegLayer = 0;
     }

      // MPEG Version
    szMpegVersion = new char[10];
    switch(m_mp3header->version)
     {
      case MPEGVERSION_2_5: strcpy_s(szMpegVersion, strlen("MPEG 2.5")+1, "MPEG 2.5"); break;
      case MPEGVERSION_2:   strcpy_s(szMpegVersion, strlen("MPEG 2")+1, "MPEG 2");   break;
      case MPEGVERSION_1:   strcpy_s(szMpegVersion, strlen("MPEG 1")+1, "MPEG 1");   break;
      default:              szMpegVersion = 0;
     }

      // Channel Mode
    szChannelMode = new char[15];
    switch(m_mp3header->channelmode)
     {
      case MP3CHANNELMODE_STEREO:         strcpy_s(szChannelMode,strlen("Stereo")+1,  "Stereo");         break;
      case MP3CHANNELMODE_JOINT_STEREO:   strcpy_s(szChannelMode, strlen("Joint Stereo")+1, "Joint Stereo");   break;
      case MP3CHANNELMODE_DUAL_CHANNEL:   strcpy_s(szChannelMode, strlen("Dual Channel")+1, "Dual Channel");   break;
      case MP3CHANNELMODE_SINGLE_CHANNEL: strcpy_s(szChannelMode, strlen("Single Channel")+1, "Single Channel"); break;
      default:                            szChannelMode = 0;
     }
   }


    /// extracts a string
  bool MP3FileInfo::m_getString(ID3_FrameID fid, char* szBuffer)
   {
    assert(m_bOK);

    ID3_Frame* frame = m_id3tag->Find(fid); // frame
    if(frame==0)
     {

       strcpy_s(szBuffer, strlen("[Not Found]") + 1, "[Not Found]");
      return false;
     }

    if(!frame->Contains(ID3FN_TEXTENC))
     {

       strcpy_s(szBuffer, strlen("[Contains No Text]") + 1, "[Contains No Text]");
      return false;
     }

    ID3_Field* field = 0;
    if(frame->Contains(ID3FN_TEXT))
     { field = frame->GetField(ID3FN_TEXT); }

      // String is an URL
    if(frame->Contains(ID3FN_URL) && (field==0))
     { field = frame->GetField(ID3FN_URL); }

    if(field==0)
     {
      delete frame;

      strcpy_s(szBuffer, strlen("[Error]") + 1, "[Error]");
      return false;
     }

    field->SetEncoding(ID3TE_ISO8859_1);
    const char* res = field->GetRawText(); // GetRawUnicodeText
    if(res==0)
     {
      delete frame;

       strcpy_s(szBuffer, strlen("[Empty]") + 1, "[Empty]");
      return false;
     }


     strcpy_s(szBuffer, strlen(res) + 1, res);
    return true;
   }


    /// extracts a string
  char* MP3FileInfo::m_getNewString(ID3_FrameID fid)
   {
    assert(m_bOK);

    ID3_Frame* frame = m_id3tag->Find(fid); // find frame
    if(frame==0) { return 0; }

    if(!frame->Contains(ID3FN_TEXTENC))
     { delete frame; return 0; } // frame contains no text

      // look for field type
    ID3_Field* field = 0;
    if(frame->Contains(ID3FN_TEXT)) // Text field
     { field = frame->GetField(ID3FN_TEXT); }

    if(frame->Contains(ID3FN_URL) && (field==0)) // URL field
     { field = frame->GetField(ID3FN_URL); }

    if(field==0) { delete frame; return 0; } // no field found

    field->SetEncoding(ID3TE_ISO8859_1); // use Latin-1 charset

    const char* res = field->GetRawText(); // TODO: GetRawUnicodeText
    char* buf = new char[strlen(res)+1]; // new string
    // copy
    strcpy_s(buf, strlen(res) + 1, res);
    return buf;
   }

My Music Player的头文件
主程序


// My Music Player.h : PROJECT_NAME 应用程序的主头文件
//

#pragma once

#ifndef __AFXWIN_H__
    #error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"
#endif

#include "resource.h"       // 主符号


// CMyMusicPlayerApp:
// 有关此类的实现,请参阅 My Music Player.cpp
//

class CMyMusicPlayerApp : public CWinAppEx
{
public:
    CMyMusicPlayerApp();

// 重写
    public:
    virtual BOOL InitInstance();

// 实现

    DECLARE_MESSAGE_MAP()

};

extern CMyMusicPlayerApp theApp;

My Music Player的实现文件


// My Music Player.cpp : 定义应用程序的类行为。
//

#include "stdafx.h"
#include "My Music Player.h"
#include "My Music PlayerDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CMyMusicPlayerApp

BEGIN_MESSAGE_MAP(CMyMusicPlayerApp, CWinAppEx)
    ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CMyMusicPlayerApp 构造

CMyMusicPlayerApp::CMyMusicPlayerApp()
{
    // TODO: 在此处添加构造代码,
    // 将所有重要的初始化放置在 InitInstance 中
}


// 唯一的一个 CMyMusicPlayerApp 对象

CMyMusicPlayerApp theApp;


// CMyMusicPlayerApp 初始化

BOOL CMyMusicPlayerApp::InitInstance()
{
    CWinAppEx::InitInstance();

    // 标准初始化
    // 如果未使用这些功能并希望减小
    // 最终可执行文件的大小,则应移除下列
    // 不需要的特定初始化例程
    // 更改用于存储设置的注册表项
    // TODO: 应适当修改该字符串,
    // 例如修改为公司或组织名
    SetRegistryKey(_T("应用程序向导生成的本地应用程序"));

    CMyMusicPlayerDlg dlg;
    m_pMainWnd = &dlg;
    INT_PTR nResponse = dlg.DoModal();
    if (nResponse == IDOK)
    {
        // TODO: 在此放置处理何时用
        //  “确定”来关闭对话框的代码
    }
    else if (nResponse == IDCANCEL)
    {
        // TODO: 在此放置处理何时用
        //  “取消”来关闭对话框的代码
    }

    // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序,
    //  而不是启动应用程序的消息泵。

    INITCOMMONCONTROLSEX InitCtrls;
    InitCtrls.dwSize = sizeof(InitCtrls);
    InitCtrls.dwICC = ICC_WIN95_CLASSES;
    InitCommonControlsEx(&InitCtrls);

    return FALSE;
}

My Music Player Dlg的头文件(主对话框)

/********************************
*类名:CMyMusicPlayerDlg
*功能:函数定义及变量声明
*文件名:My Music PlayerDlg.h
*********************************/

// My Music PlayerDlg.h : 头文件
//

/********************************
*常量和枚举型定义
*********************************/
const int ID_PLAYTIMER = 1;         //定时器ID

typedef enum _tagPlayMode           //各个播放模式的枚举值
{
    SEQUENCE_MODE = 0,              //顺序播放
    RANDOM_MODE   = 1,              //随机播放
    SINGLE_LOOP   = 2,              //单曲循环
    SINGLE_PLAY   = 3               //单曲播放

}PLAYMODE;

typedef enum _tagColumnWidth        //列表控件中每个列的宽度值
{
    SERIALNUMBERWIDTH = 40,         //序号
    FILENAMEWIDTH     = 150,        //文件名
    FILEPATHWIDTH     = 250,        //文件路径
    FILEDURATIONWIDTH = 100         //文件时长

}COLUMNWIDTH;

typedef enum _tagColumnIndex        //列表控件中各个列的索引值
{
    ID_SERIALNUMBER = 0,            //序号
    ID_FILENAME = 1,                //文件名
    ID_FILEPATH = 2,                //文件路径
    ID_FILEDURATION = 3             //文件时长
}COLUMNINDEX;


#pragma once
#include "afxcmn.h"
#include "afxwin.h"
#include "NiceSlider.h"
#include "MP3FileInfo.h"


// CMyMusicPlayerDlg 对话框
class CMyMusicPlayerDlg : public CDialog
{
// 构造
public:
    CMyMusicPlayerDlg(CWnd* pParent = NULL);        // 标准构造函数

// 对话框数据
    enum { IDD = IDD_MYMUSICPLAYER_DIALOG };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持


// 实现
protected:
    HICON m_hIcon;

    // 生成的消息映射函数
    virtual BOOL OnInitDialog();                        //对话框初始化函数
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()

//成员变量
protected:

    CEdit m_edtSongTitle;                                   //显示歌曲文件名的编辑框
    CEdit m_edtArtist;                                      //显示歌曲艺术家的编辑框
    CEdit m_edtAlbum;                                       //显示歌曲专辑的编辑框
    CEdit m_edtYear;                                        //显示歌曲发行年份的编辑框
    CEdit m_edtSongBitrate;                                 //显示歌曲文件名的编辑框
    CEdit m_edtSongGenre;                                   //显示歌曲文件名的编辑框

    CNiceSliderCtrl m_position;                             //显示播放进度控件
    CNiceSliderCtrl sliderVol;                              //音量控制
    CListCtrl m_myListCtrl;                                 //显示播放列表控件
    CComboBox m_playmode;                                   //显示播放模式的组合框
    CMenu* pMainMenu;                                       //主菜单
    CMenu* pSubPlayMenu;                                    //播放控制菜单(用于更新菜单项)
    MP3FileInfo mp3info;                                    //获取mp3的tag信息 对象

    ITaskbarList3* pTaskbar;                                //用于支持任务栏显示播放进度
    HACCEL  hAccel;                                         //键盘加速键句柄

    WORD    m_wDeviceID;                                    //MCI设备ID
    TCHAR   strMciError[MAX_PATH];                          //用于保存mci设备错误代码

    CString m_strFilePath;                                  //当前播放文件路径
    CString m_strFileName;                                  //当前播放文件名称
    CString m_strFileDuration;                              //当前播放文件的时长
    CString m_strTotalLength;                               //文件总时长(字符串)
    CString m_strCurrentLength;                             //文件当前播放时间(字符串)

    CString m_strSongTitle;                                 //歌曲名称
    CString m_strArtist;                                    //艺术家
    CString m_strAlbum;                                     //专辑
    CString m_strYear;                                      //发行年
    CString m_strSongBitrate;                               //比特率
    CString m_strSongGenre;                                 //流派

    DWORD   dCurrentPos;                                    //当前播放位置(毫秒为单位)
    DWORD   m_dLength;                                      //音频文件的长度(毫秒为单位)

    int     m_nPlayMode;                                    //播放模式索引
    int     m_nCurrentSelection;                            //列表控件当前位置的索引值
    BOOL    bPause ;                                        //暂停标记

//功能函数
public:
   BOOL InitControls(void);                                 //初始化界面控件
   BOOL InitMyMenu(void);                                   //初始化菜单
   BOOL InitComboxBox(void);                                //初始化播放模式组合框
   BOOL InitMyListCtrl(void);                               //初始化播放列表
   void TaskBarInit(void);                                  //任务栏初始化

   BOOL LoadFile(void);                                     //打开文件函数
   void GetMp3Info(CString strFilePath);                    //获得音频的ID3 Tag
   BOOL PlayFile(CString szFileName);                       //播放文件函数
   void PauseMe();                                          //暂停函数
   void SetWindowTitle(CString fileName, int nPlayingFlag); // 设置窗口标题
   void GoPrevious(void);                                   //上一曲函数
   void GoNext(void);                                       //下一曲函数
   void GoAhead(void);                                      //快进函数
   void GoBack(void);                                       //快退函数
   void AddFileToPlayList(void);                            //增加项目函数
   void DeleteItem(void);                                   //删除项目函数

   void SetVolume(int Vol);                                 //设置音量大小函数 
   void UpdateCurrentPosText(void);                         //更新播放位置
   void SetPlayMode(void);                                  //设置各个播放模式
   CString ConvertTimeToString(int );                       //将文件毫秒数转换为分钟和秒
   void GetCurrentSelection(void);                          //当前列表控件选中位置的索引
   int  ParseFilePath(CString strFilePath);                 //从文件路径中分析出文件名

//支持函数
public:
    virtual BOOL PreTranslateMessage(MSG* pMsg);                                 //处理ESCAPE键和Enter键退出对话框
    afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu); //使对话框支持菜单项更新命令 (Code from MSDN)
    afx_msg void OnTimer(UINT_PTR nIDEvent);                                    //定时器:用于更新播放进度的位置
    afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);    //处理播放进度滑块和音量调节滑块位置变化
    afx_msg void OnDropFiles(HDROP hDropInfo);                                 //拖放
    afx_msg void OnClose();                                                    //关闭
//按钮映射函数
public:
   afx_msg void OnBnClickedBtnopen();                   //载入并播放按钮
   afx_msg void OnBnClickedBtnpause();                  //暂停按钮
   afx_msg void OnBnClickedBtnoprevious();              //上一曲
   afx_msg void OnBnClickedBtnnext();                   //下一曲
   afx_msg void OnBnClickedBtnahead();                  //快进按钮
   afx_msg void OnBnClickedBtnback();                   //快退按钮
   afx_msg void OnBnClickedBtnadd();                    //增加歌曲   
   afx_msg void OnBnClickedBtndelete();                 //删除歌曲

//菜单项的映射函数
public:
    afx_msg void OnFileOpen();
    afx_msg void OnFileAddfolder();
    afx_msg void OnAppExit();
    afx_msg void OnHelpAbout();
    afx_msg void OnControlPlay();
    afx_msg void OnControlPause();
    afx_msg void OnControlPrevious();
    afx_msg void OnControlNext();
    afx_msg void OnControlAhead();
    afx_msg void OnControlBack();
    afx_msg void OnModeSequence();                      
    afx_msg void OnModeRandom();
    afx_msg void OnModeSingleloop();
    afx_msg void OnModeSingleplay();

//播放模式菜单项更新
    afx_msg void OnUpdateModeSequence(CCmdUI *pCmdUI);
    afx_msg void OnUpdateModeRandom(CCmdUI *pCmdUI);
    afx_msg void OnUpdateModeSingleloop(CCmdUI *pCmdUI);
    afx_msg void OnUpdateModeSingleplay(CCmdUI *pCmdUI);
//播放列表控件右键菜单逻辑
public:
    afx_msg void OnContextmenuPlayfile();
    afx_msg void OnContextmenuPause();
    afx_msg void OnContextmenuPrevious();
    afx_msg void OnContextmenuNext();
    afx_msg void OnContextmenuLoadfile();
    afx_msg void OnContextmenuDeleteitem();
    afx_msg void OnContextmenuOpenfolder();

//列表控件和播放模式组合框控件的消息映射
public:
    afx_msg void OnNMRClickPlaylist(NMHDR *pNMHDR, LRESULT *pResult);   //右键列表控件消息映射
    afx_msg void OnNMDblclkPlaylist(NMHDR *pNMHDR, LRESULT *pResult);   //双击列表控件消息
    afx_msg void OnNMClickPlaylist(NMHDR *pNMHDR, LRESULT *pResult);    //单击列表控件消息
    afx_msg void OnCbnSelchangeComplaymode();                           //播放模式组合框内容变化
    afx_msg void OnLvnItemchangedPlaylist(NMHDR *pNMHDR, LRESULT *pResult); //播放列表控件项目变化,用于更新歌曲数目
};

My Music Player Dlg的实现文件

/****************
*类名:CMyMusicPlayerDlg
*功能:绘制程序界面,实现各个功能函数。
*文件名:My Music PlayerDlg.cpp
*/

// My Music PlayerDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "My Music Player.h"
#include "My Music PlayerDlg.h"
#include "resource.h"
#include "afxcmn.h"
#include "AboutDlg.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif



// CMyMusicPlayerDlg 对话框


CMyMusicPlayerDlg::CMyMusicPlayerDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CMyMusicPlayerDlg::IDD, pParent)
    , dCurrentPos(0)
    , m_dLength(0)
    , bPause(FALSE)
    , m_strFileName(_T(""))
    , m_strFilePath(_T("")) 
    , pMainMenu(NULL)
    , pTaskbar(NULL)
    , m_nPlayMode(0)
    , m_nCurrentSelection(0)
    , m_strSongTitle(_T(""))
    , m_strArtist(_T(""))
    , m_strAlbum(_T(""))
    , m_strYear(_T(""))
    , m_strSongBitrate(_T(""))
{
    m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);

}

void CMyMusicPlayerDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_SLIDERPOS, m_position);
    DDX_Control(pDX, IDC_SLIDERVOL, sliderVol);
    DDX_Control(pDX, IDC_COMPLAYMODE, m_playmode);
    DDX_Control(pDX, IDC_PLAYLIST, m_myListCtrl);
    DDX_Control(pDX, IDC_EDIT_SONGTITLE, m_edtSongTitle);
    DDX_Control(pDX, IDC_EDIT_ARTIST, m_edtArtist);
    DDX_Control(pDX, IDC_EDIT_ALBUM, m_edtAlbum);
    DDX_Control(pDX, IDC_EDIT_YEAR, m_edtYear);
    DDX_Control(pDX, IDC_EDIT_SONGBITRATE, m_edtSongBitrate);
    DDX_Control(pDX, IDC_EDIT_GENRE, m_edtSongGenre);
}

BEGIN_MESSAGE_MAP(CMyMusicPlayerDlg, CDialog)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()

    //}}AFX_MSG_MAP
    ON_WM_INITMENUPOPUP()
    ON_WM_TIMER()
    ON_WM_HSCROLL()
    ON_WM_DROPFILES()
    ON_WM_CLOSE()

    ON_BN_CLICKED(IDC_BTNOPEN, &CMyMusicPlayerDlg::OnBnClickedBtnopen)
    ON_BN_CLICKED(IDC_BTNPAUSE, &CMyMusicPlayerDlg::OnBnClickedBtnpause)
    ON_BN_CLICKED(IDC_BTNPREVIOUS, &CMyMusicPlayerDlg::OnBnClickedBtnoprevious)
    ON_BN_CLICKED(IDC_BTNNEXT, &CMyMusicPlayerDlg::OnBnClickedBtnnext)  
    ON_BN_CLICKED(IDC_BTNAHEAD, &CMyMusicPlayerDlg::OnBnClickedBtnahead)
    ON_BN_CLICKED(IDC_BTNBACK, &CMyMusicPlayerDlg::OnBnClickedBtnback)
    ON_BN_CLICKED(IDC_BTNADD, &CMyMusicPlayerDlg::OnBnClickedBtnadd)
    ON_BN_CLICKED(IDC_BTNDELETE, &CMyMusicPlayerDlg::OnBnClickedBtndelete)

    ON_COMMAND(IDM_FILE_OPEN, &CMyMusicPlayerDlg::OnFileOpen)
    ON_COMMAND(IDM_FILE_ADDFOLDER, &CMyMusicPlayerDlg::OnFileAddfolder)
    ON_COMMAND(IDM_APP_EXIT, &CMyMusicPlayerDlg::OnAppExit)
    ON_COMMAND(IDM_HELP_ABOUT, &CMyMusicPlayerDlg::OnHelpAbout) 
    ON_COMMAND(IDM_CONTROL_PLAY, &CMyMusicPlayerDlg::OnControlPlay)
    ON_COMMAND(IDM_CONTROL_PAUSE, &CMyMusicPlayerDlg::OnControlPause)
    ON_COMMAND(IDM_CONTROL_PREVIOUS, &CMyMusicPlayerDlg::OnControlPrevious)
    ON_COMMAND(IDM_CONTROL_NEXT, &CMyMusicPlayerDlg::OnControlNext)
    ON_COMMAND(IDM_CONTROL_AHEAD, &CMyMusicPlayerDlg::OnControlAhead)
    ON_COMMAND(IDM_CONTROL_BACK, &CMyMusicPlayerDlg::OnControlBack) 
    ON_COMMAND(ID_MODE_SEQUENCE, &CMyMusicPlayerDlg::OnModeSequence)
    ON_COMMAND(ID_MODE_RANDOM, &CMyMusicPlayerDlg::OnModeRandom)
    ON_COMMAND(ID_MODE_SINGLELOOP, &CMyMusicPlayerDlg::OnModeSingleloop)
    ON_COMMAND(ID_MODE_SINGLEPLAY, &CMyMusicPlayerDlg::OnModeSingleplay)

    ON_UPDATE_COMMAND_UI(ID_MODE_SEQUENCE, &CMyMusicPlayerDlg::OnUpdateModeSequence)
    ON_UPDATE_COMMAND_UI(ID_MODE_RANDOM, &CMyMusicPlayerDlg::OnUpdateModeRandom)
    ON_UPDATE_COMMAND_UI(ID_MODE_SINGLELOOP, &CMyMusicPlayerDlg::OnUpdateModeSingleloop)
    ON_UPDATE_COMMAND_UI(ID_MODE_SINGLEPLAY, &CMyMusicPlayerDlg::OnUpdateModeSingleplay)

    ON_COMMAND(IDM_CONTEXTMENU_PLAYFILE, &CMyMusicPlayerDlg::OnContextmenuPlayfile)
    ON_COMMAND(IDM_CONTEXTMENU_PAUSE, &CMyMusicPlayerDlg::OnContextmenuPause)
    ON_COMMAND(IDM_CONTEXTMENU_PREVIOUS, &CMyMusicPlayerDlg::OnContextmenuPrevious)
    ON_COMMAND(IDM_CONTEXTMENU_NEXT, &CMyMusicPlayerDlg::OnContextmenuNext)
    ON_COMMAND(IDM_CONTEXTMENU_LOADFILE, &CMyMusicPlayerDlg::OnContextmenuLoadfile)
    ON_COMMAND(IDM_CONTEXTMENU_DELETEITEM, &CMyMusicPlayerDlg::OnContextmenuDeleteitem)
    ON_COMMAND(IDM_CONTEXTMENU_OPENFOLDER, &CMyMusicPlayerDlg::OnContextmenuOpenfolder)

    ON_CBN_SELCHANGE(IDC_COMPLAYMODE, &CMyMusicPlayerDlg::OnCbnSelchangeComplaymode)

    ON_NOTIFY(NM_RCLICK, IDC_PLAYLIST, &CMyMusicPlayerDlg::OnNMRClickPlaylist)
    ON_NOTIFY(NM_DBLCLK, IDC_PLAYLIST, &CMyMusicPlayerDlg::OnNMDblclkPlaylist)
    ON_NOTIFY(NM_CLICK, IDC_PLAYLIST, &CMyMusicPlayerDlg::OnNMClickPlaylist)
    ON_NOTIFY(LVN_ITEMCHANGED, IDC_PLAYLIST, &CMyMusicPlayerDlg::OnLvnItemchangedPlaylist)
END_MESSAGE_MAP()


// CMyMusicPlayerDlg 消息处理程序

BOOL CMyMusicPlayerDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // 将“关于...”菜单项添加到系统菜单中。

    // IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);         // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    // TODO: 对话框其他初始化代码

    InitControls();                 //初始化控件
    InitMyMenu();                   //初始化菜单
    InitComboxBox();                //初始化组合框控件
    InitMyListCtrl();               //初始化列表控件

    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CMyMusicPlayerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialog::OnSysCommand(nID, lParam);
    }
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CMyMusicPlayerDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // 使图标在工作区矩形中居中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMyMusicPlayerDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}


/************************************************************************/
/* 函数名:InitControls
/* 参数:无     返回值:初始化成功返回TRUE
/* 描述:用于初始化对话框标题、对话框中按钮、播放进度滑块的数值并加载快捷键                                      */
/************************************************************************/

BOOL CMyMusicPlayerDlg::InitControls(void)
{
    /************************************************************************/
    /* 初始化每个控件内容和位置                                                        */            
    /************************************************************************/  
    this->SetWindowText(TEXT("My Music Player"));

    this->SetDlgItemText(IDC_CURRENT_POS, TEXT("00:00"));
    this->SetDlgItemText(IDC_TOTAL_LENGTH, TEXT("00:00"));

    m_position.SetPos(0);                //初始化播放进度控件滑块值
    sliderVol.SetRange(0,100);           //设置音量控件的范围
    sliderVol.SetPos(0);                //初始化音量控件滑块值

    hAccel = ::LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_ACCELERATOR1));
    return TRUE;
}
/************************************************************************/
/* 函数名:InitMyMenu
/* 参数:无     返回值:初始化成功返回TRUE
/* 描述:初始化并加载主菜单,同时并获得播放控制菜单的句柄,用于更新菜单项状态   */
/************************************************************************/
BOOL CMyMusicPlayerDlg::InitMyMenu(void)
{

    pMainMenu  =  new CMenu();
    pMainMenu->LoadMenu(IDR_MAINFRAME);         //  IDR_MAINFRAME为菜单ID
    pSubPlayMenu = pMainMenu->GetSubMenu(1);    //得到播放控制菜单的句柄,索引从0开始
    SetMenu(pMainMenu);
    pMainMenu->Detach();
    return TRUE;
}
/************************************************************************/
/* 函数名:InitComboxBox
/* 参数:无     返回值:初始化成功返回TRUE
/* 描述:初始化播放模式组合框的项目                                        */
/************************************************************************/
BOOL CMyMusicPlayerDlg::InitComboxBox(void)
{
    m_playmode.InsertString(-1,TEXT("顺序播放"));
    m_playmode.InsertString(-1,TEXT("随机播放"));
    m_playmode.InsertString(-1,TEXT("单曲循环"));
    m_playmode.InsertString(-1,TEXT("单曲播放"));
    m_playmode.SetCurSel(0);

    return TRUE;
}
/************************************************************************/
/* 函数名:InitMyListCtrl
/* 参数:无     返回值:初始化成功返回TRUE
/* 描述:初始化列表控件的风格,并初始化列表控件的列内容                                      */
/************************************************************************/
BOOL CMyMusicPlayerDlg::InitMyListCtrl(void)
{
    m_myListCtrl.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT );
    m_myListCtrl.ModifyStyle(0,LVS_REPORT|LVS_SHOWSELALWAYS|LVS_SINGLESEL);

    LVCOLUMN lvc;
    lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH ;
    lvc.fmt  = LVCFMT_CENTER ;
    lvc.cx   = SERIALNUMBERWIDTH ;
    lvc.pszText = _T("序号");

    m_myListCtrl.InsertColumn(ID_SERIALNUMBER, &lvc);

    lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
    lvc.fmt = LVCFMT_LEFT;
    lvc.cx = FILENAMEWIDTH;
    lvc.pszText = _T("文件名");

    m_myListCtrl.InsertColumn(ID_FILENAME, &lvc);

    lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
    lvc.fmt = LVCFMT_LEFT;
    lvc.cx = FILEPATHWIDTH;
    lvc.pszText = _T("文件路径");

     m_myListCtrl.InsertColumn(ID_FILEPATH, &lvc);

     lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
     lvc.fmt = LVCFMT_CENTER;
     lvc.cx = FILEDURATIONWIDTH;
     lvc.pszText = _T("时长");

     m_myListCtrl.InsertColumn(ID_FILEDURATION, &lvc);

    return 0;
}
/************************************************************************/
/* 函数名:TaskBarInit
/* 参数:无     返回值:无
/* 描述:初始化COM组件,主要用于在任务栏上显示歌曲播放进度。                                      */
/************************************************************************/
void CMyMusicPlayerDlg::TaskBarInit(void)
{
    CoInitialize(0);        //初始化COM组件。
    CoCreateInstance(CLSID_TaskbarList , NULL , CLSCTX_INPROC_SERVER , IID_PPV_ARGS (&pTaskbar));
    pTaskbar->HrInit();
}

/************************************************************************/
/* 函数名:LoadFile
/* 参数:无     返回值:成功加载返回TRUE,否则返回FALSE
/* 描述:用于打开选择文件对话框,加载文件。                                 */
/************************************************************************/

BOOL CMyMusicPlayerDlg::LoadFile(void)
{
    //打开文件对话框支持的文件扩展名
    LPCTSTR szFilters = TEXT("支持的音频文件(*.wav;*mp3;*.wma) |*.wav;*mp3;*.wma|所有文件 (*.*)|*.*||");
   //创建一个打开文件对话框对象
   CFileDialog FileDlg(TRUE,TEXT("mp3"),NULL,OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST , szFilters );
   if(IDCANCEL == FileDlg.DoModal())
   {
          return FALSE;
   }
   else 
   {
        m_strFilePath = FileDlg.GetPathName();                  //文件路径名
        m_strFileName = FileDlg.GetFileTitle();                 //文件名
        GetMp3Info(m_strFilePath);                              //获取mp3的tag信息
        this->SetWindowText(m_strFileName + TEXT(" 状态:播放")); //设置对话框窗口标题
        return TRUE;
   }
   return FALSE;
}
/************************************************************************/
/* 函数名:GetMp3Info 
/* 参数:文件路径
/* 描述:用于获取音频文件的歌手,艺术家,专辑,发行时间等信息,支持ID3v1, ID3V2的tag信息读取 */
/************************************************************************/
void CMyMusicPlayerDlg::GetMp3Info(CString strFilePath)
{
    //由于MP3Info类只支持多字节,所以将宽字节转换为多字节
    int len = WideCharToMultiByte( CP_ACP , 0 , strFilePath , strFilePath.GetLength() , NULL , 0 , NULL , NULL );
    char* pAscii =new char[len+1];
    len = WideCharToMultiByte( CP_ACP , 0 , strFilePath , strFilePath.GetLength() , pAscii , len +1 , NULL ,NULL );
    pAscii[len] = 0;

    if(!mp3info.Init(pAscii))
    {
        return ;
    }
    else
    {

            m_strSongTitle =  mp3info.szTitle;      
            m_strArtist = mp3info.szArtist;
            m_strAlbum = mp3info.szAlbum;
            m_strYear = mp3info.szYear;
            m_strSongBitrate = mp3info.szBitRate;
            m_strSongGenre = mp3info.szGenre;

            mp3info.Free();

            m_edtSongTitle.SetWindowText(m_strSongTitle);
            m_edtArtist.SetWindowText(m_strArtist);
            m_edtAlbum.SetWindowText(m_strAlbum);
            m_edtYear.SetWindowText(m_strYear);
            m_edtSongBitrate.SetWindowText(m_strSongBitrate);
            m_edtSongGenre.SetWindowText(m_strSongGenre);

            UpdateData(FALSE);
    }

}

/************************************************************************/
/* 函数名:PlayFile 
/* 参数:歌曲文件的路径
/* 描述:播放音频文件                                */
/************************************************************************/

BOOL CMyMusicPlayerDlg::PlayFile(CString szFilePath)
{

  bPause = FALSE;                    //初始化暂停标记为TRUE

  SetTimer(ID_PLAYTIMER,1000,NULL); //初始化定时器,用于显示播放进度

  mciSendCommand(m_wDeviceID,MCI_CLOSE, 0, NULL); //在打开新文件之前,先关闭之前的文件

   MCI_OPEN_PARMS mciOpen; //打开参数
   MCI_PLAY_PARMS mciPlay; //播放参数
   mciOpen.lpstrElementName = szFilePath.GetBuffer(szFilePath.GetLength()); //设置播放路径
   szFilePath.ReleaseBuffer(szFilePath.GetLength());

   //发送打开命令
   MCIERROR err = mciSendCommand(NULL,MCI_OPEN, MCI_OPEN_ELEMENT, (DWORD)(LPVOID)&mciOpen);
    /*MCI_OPEN_ELEMENT 表示MCI_OPEN_PARMS的lpstrElementName有效 
      MCI_OPEN_TYPE表示MCI_OPEN_PARMS的lpstrDeviceType有效 
      MCI_WAIT表示命令发送后会一直等待,直到操作完成 
      (如果是MCI_NOTIFY,则表示发送命令后会立即返回,当操作真正完毕后发出通告消息)*/
   if (err) 
   {
      mciGetErrorString(err,strMciError,sizeof(strMciError));
      if (IDOK == AfxMessageBox(strMciError, MB_OK | MB_ICONERROR))
      {
          return FALSE ;
      } 
   }
   else 
   {

      m_wDeviceID = mciOpen.wDeviceID ;      //保存设备ID    
      MCI_STATUS_PARMS mciStatus;            //声明保存文件信息的结构体
      mciStatus.dwItem = MCI_STATUS_LENGTH ; //需要获取的项
      mciSendCommand(m_wDeviceID,MCI_STATUS,MCI_WAIT |  MCI_STATUS_ITEM,(DWORD)(LPVOID)&mciStatus); //MCI_STATUS_ITEM 表示MCI_STATUS_PARMS的dwItem有效

      //mciSendCommand发送MCI_STATUS命令获得MIC_STATUS_LENGTH信息,并将信息保存在变量mciStatus中。
      m_dLength = mciStatus.dwReturn ; // The dwReturn member is set to the total media length. (From MSDN)    
      mciSendCommand(m_wDeviceID,MCI_PLAY,0 ,(DWORD)(LPVOID)&mciPlay); //发送播放命令

      pSubPlayMenu->CheckMenuItem(IDM_CONTROL_PLAY,MF_CHECKED);//打开文件后初始化各个控件的数值
      pSubPlayMenu->CheckMenuItem(IDM_CONTROL_PAUSE, MF_UNCHECKED);
      m_position.SetRange(0,m_dLength);             //设置播放进度控件的范围
      m_position.SetPos(0);                         //设置播放进度控件的初始值
      sliderVol.SetPos(50);                         //初始化音量控件的滑块位置

      CString strVolume;
      strVolume.Format(TEXT("%d"),50);
      this->SetDlgItemText(IDC_EDITVOL,strVolume);
      SetVolume(50);                                //设置音频的初始音量大小

      m_strTotalLength = ConvertTimeToString(m_dLength);
      this->SetDlgItemText(IDC_TOTAL_LENGTH,m_strTotalLength);

      UpdateData(FALSE);
      TaskBarInit();                                //初始化Taskbar
      bPause = TRUE;                                //暂停标记
      return TRUE;
 } 
 return FALSE ;
}


/************************************************************************/
/* 函数名:PauseMe
/* 参数:无
/* 描述:暂停当前播放文件。                                             */
/************************************************************************/

void CMyMusicPlayerDlg::PauseMe()
{
   if (bPause)                          //如果bPause为真
   {
       bPause = FALSE ; //toggle it
       SetWindowTitle(m_strFileName, bPause);
      MCI_GENERIC_PARMS mciPause; //mci暂停参数

      mciSendCommand(m_wDeviceID,MCI_PAUSE,0,(DWORD)(LPVOID)&mciPause);//发送暂停命令
      SetDlgItemText(IDC_BTNPAUSE,TEXT("播放"));

      //设置播放列表中菜单项 暂停 为选中
      pSubPlayMenu->CheckMenuItem(IDM_CONTROL_PAUSE,MF_CHECKED);
      //设置播放列表中菜单项 播放 为不选中
      pSubPlayMenu->CheckMenuItem(IDM_CONTROL_PLAY,MF_UNCHECKED);

   }
   else
   {
       bPause = TRUE ;
      SetWindowTitle(m_strFileName, bPause);
      MCI_PLAY_PARMS mciPlay;
      mciSendCommand(m_wDeviceID,MCI_PLAY,0,(DWORD)(LPVOID)&mciPlay);//发送播放命令
      SetDlgItemText(IDC_BTNPAUSE,TEXT("暂停"));

      pSubPlayMenu->CheckMenuItem(IDM_CONTROL_PLAY,MF_CHECKED);
      pSubPlayMenu->CheckMenuItem(IDM_CONTROL_PAUSE,MF_UNCHECKED);

   }
}
// 设置窗口标题
void CMyMusicPlayerDlg::SetWindowTitle(CString fileName, int nPlayingFlag)
{
    if (nPlayingFlag)
    {
        this->SetWindowText(fileName + TEXT(" 状态:播放"));
        return ;
    }
    else
    {
        this->SetWindowText(fileName + TEXT(" 状态:暂停"));
        return ;
    }

}

/************************************************************************/
/* 函数名:GoPrevious
/* 参数:无
/* 描述:上一曲功能函数                                */
/************************************************************************/

void CMyMusicPlayerDlg::GoPrevious(void)
{

    if (0 == m_myListCtrl.GetItemCount())
    {
        mciSendCommand(NULL, MCI_CLOSE, 0, 0);
        return ;
    }
    else 
    {
        GetCurrentSelection();
        if (m_nCurrentSelection == 0) //如果在第一个位置
        {
            m_nCurrentSelection = m_myListCtrl.GetItemCount() - 1; //把选中项倒置到最后
        }
        else
        {
            m_nCurrentSelection = m_nCurrentSelection - 1; 
        }
        m_myListCtrl.SetFocus();
        m_myListCtrl.SetItemState(m_nCurrentSelection, LVIS_SELECTED, LVIS_SELECTED);   //设置选中行
        m_strFileName = m_myListCtrl.GetItemText(m_nCurrentSelection, ID_FILENAME); //获得文件名
        m_strFilePath = m_myListCtrl.GetItemText(m_nCurrentSelection, ID_FILEPATH); //得到选中位置的文本
        PlayFile(m_strFilePath);            //播放文件
        GetMp3Info(m_strFilePath);                                   
        SetWindowTitle(m_strFileName, bPause);
    }



}
/************************************************************************/
/* 函数名:GoNext
/* 参数:无
/* 描述:下一曲功能函数                                */
/************************************************************************/
void CMyMusicPlayerDlg::GoNext(void)
{

    if (0 == m_myListCtrl.GetItemCount())
    {
        mciSendCommand(NULL, MCI_CLOSE, 0 , 0);
        return ;
    }
    else 
    {
        GetCurrentSelection();                              //获得当前播放列表的选中项位置
        if (m_nCurrentSelection ==  m_myListCtrl.GetItemCount() - 1) //如果在最后一个位置
        {
            m_nCurrentSelection = 0 ; //把当前索引移到第一个位置
        }
        else
        {
            m_nCurrentSelection = m_nCurrentSelection + 1;

        }

        m_myListCtrl.SetFocus();
        m_myListCtrl.SetItemState(m_nCurrentSelection, LVIS_SELECTED, LVIS_SELECTED);
        m_strFileName = m_myListCtrl.GetItemText(m_nCurrentSelection, ID_FILENAME);
        m_strFilePath = m_myListCtrl.GetItemText(m_nCurrentSelection, ID_FILEPATH); //得到选中位置的文本

        //播放文件
        PlayFile(m_strFilePath);
        GetMp3Info(m_strFilePath);
        SetWindowTitle(m_strFileName, bPause);
    }

}
/************************************************************************/
/* 函数名:GoAhead
/* 参数:无
/* 描述:快进5秒功能函数                                */
/************************************************************************/

void CMyMusicPlayerDlg::GoAhead(void)
{
    int iPosition = m_position.GetPos(); //得到slider控件的滑块位置

    MCI_SEEK_PARMS mciSeek;             //mci设备查找参数
    MCI_PLAY_PARMS mciPlay;

    mciSeek.dwTo = iPosition;           //设置seek的位置
    mciSeek.dwTo += 5000;               //增加5秒

    mciPlay.dwFrom = mciSeek.dwTo ;     //设置播放的位置dwFrom

    mciSendCommand (m_wDeviceID, MCI_SEEK, MCI_TO
        ,(DWORD)(LPVOID)
        &mciSeek);

    mciSendCommand(m_wDeviceID,MCI_PLAY,MCI_FROM | MCI_NOTIFY, (DWORD)(LPVOID)
        &mciPlay);
    //MCI_FROM 使dwForm有效

    m_position.SetPos(mciPlay.dwFrom); //设置滑块的新位置

}
/************************************************************************/
/* 函数名:GoBack
/* 参数:无
/* 描述:快退5秒功能函数                                */
/************************************************************************/

void CMyMusicPlayerDlg::GoBack(void)
{
    int iPosition = m_position.GetPos(); //得到slider控件的滑块位置

    MCI_SEEK_PARMS mciSeek;  
    MCI_PLAY_PARMS mciPlay;

    mciSeek.dwTo = iPosition; //设置跳转后的位置
    mciSeek.dwTo -= 5000;

    mciPlay.dwFrom = mciSeek.dwTo ; //设置播放位置

    mciSendCommand (m_wDeviceID, MCI_SEEK, MCI_TO
        ,(DWORD)(LPVOID)
        &mciSeek);

    mciSendCommand(m_wDeviceID,MCI_PLAY,MCI_FROM | MCI_NOTIFY, (DWORD)(LPVOID)
        &mciPlay);

    m_position.SetPos(mciPlay.dwFrom);
}

/************************************************************************/
/* 函数名:AddFileToPlayList
/* 参数:无
/* 描述:增加歌曲函数,同时在列表控件增加项目。                                 */
/************************************************************************/
void CMyMusicPlayerDlg::AddFileToPlayList(void)
{

    LVITEM  item;            
    int     nIndex;              //当前索引位置(行)
    CString strTmp; 

    item.mask = LVIF_TEXT;  
    item.iSubItem = 0;

    //If 'm_listListOperations.GetItemCount() <= 0' evaluates to TRUE then 0, 
    //else  value returned by 'm_listListOperations.GetItemCount()'
    //iItem holds the current index
    item.iItem = (m_myListCtrl.GetItemCount() <= 0) ? 0 : m_myListCtrl.GetItemCount(); 
    strTmp.Format(TEXT("%d"), ++item.iItem);                //格式化当前索引
    item.pszText = strTmp.GetBuffer(strTmp.GetLength());    //在第一列插入序号

    nIndex = m_myListCtrl.InsertItem(&item);                //在第一列插入序号
    m_myListCtrl.SetItemText(nIndex, ID_FILENAME, m_strFileName);   //second column of the ListCtrl
    m_myListCtrl.SetItemText(nIndex, ID_FILEPATH, m_strFilePath);
    m_myListCtrl.SetItemText(nIndex, ID_FILEDURATION, m_strTotalLength);
    m_myListCtrl.SetFocus();
    m_myListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
}

/************************************************************************/
/* 函数名:DeleteItem
/* 参数:无
/* 描述:删除歌曲项目,同时在列表控件删除文本。                                 */
/************************************************************************/
void CMyMusicPlayerDlg::DeleteItem(void)
{

    CString strTmp;

     GetCurrentSelection();
    strTmp = m_myListCtrl.GetItemText(m_nCurrentSelection, ID_FILEPATH);

    if (strTmp == m_strFilePath)
    {
        m_myListCtrl.DeleteItem(m_nCurrentSelection);
        mciSendCommand(m_wDeviceID, MCI_STOP, 0, 0);
        InitControls();
    }
    else 
    {
        m_myListCtrl.DeleteItem(m_nCurrentSelection);
        m_nCurrentSelection--;
        m_myListCtrl.SetFocus();
        m_myListCtrl.SetItemState(m_nCurrentSelection, LVIS_SELECTED, LVIS_SELECTED);
    }
}
/************************************************************************/
/* 函数名:SetVolume
/* 参数: 音量值:Vol, 类型:int
/* 描述:增加歌曲函数,同时在列表框增加文本。                                 */
/************************************************************************/

void CMyMusicPlayerDlg::SetVolume(int Vol)
{
    MCI_DGV_SETAUDIO_PARMS mciSetAudioPara; //设置音量参数

    mciSetAudioPara.dwItem = MCI_DGV_SETAUDIO_VOLUME; 
    mciSetAudioPara.dwCallback = (DWORD_PTR)this->GetSafeHwnd();
    //设置音量大小
    mciSetAudioPara.dwValue = Vol * 10; //here is the value of the Volume(0--1000) 
    mciSendCommand(m_wDeviceID, MCI_SETAUDIO, MCI_DGV_SETAUDIO_VALUE | MCI_DGV_SETAUDIO_ITEM, (DWORD)(LPVOID)&mciSetAudioPara); 
}

/************************************************************************/
/* 函数名:UpdatePosition
/* 参数:无
/* 描述:更新播放时间控件中的文本                                          */
/************************************************************************/
void CMyMusicPlayerDlg::UpdateCurrentPosText(void) 
{
    MCI_STATUS_PARMS mciStatus;

    mciStatus.dwItem = MCI_STATUS_POSITION;
    mciSendCommand(m_wDeviceID,MCI_STATUS,MCI_WAIT|MCI_STATUS_ITEM,(DWORD)(LPVOID)&mciStatus);

    int dCurrentPos = mciStatus.dwReturn;
    m_strCurrentLength = ConvertTimeToString(dCurrentPos);  //将得到的毫秒转换为分钟和秒
    SetDlgItemText(IDC_CURRENT_POS,m_strCurrentLength);
}
/************************************************************************/
/* 函数名:SetPlayMode
/* 参数:无
/* 描述:设置播放模式并播放文件                                               */
/************************************************************************/
void CMyMusicPlayerDlg::SetPlayMode(void)
{
    srand((unsigned int)time(NULL));    //初始化随机种子

    int randNum = 0;
    int nCurrentSel;

    switch (m_nPlayMode)
    {
    case SEQUENCE_MODE:
            GoNext();
        break;
    case RANDOM_MODE:
            randNum = rand() % m_myListCtrl.GetItemCount();
            m_myListCtrl.SetFocus();
            m_myListCtrl.SetItemState(randNum,LVIS_SELECTED,  LVIS_SELECTED);
            nCurrentSel  =  m_myListCtrl.GetNextItem  (-1,  LVNI_SELECTED); //得到选中行的索引位置
            m_strFilePath =  m_myListCtrl.GetItemText(nCurrentSel,ID_FILEPATH);
            m_strFileName =  m_myListCtrl.GetItemText(nCurrentSel, ID_FILENAME);
            PlayFile(m_strFilePath);
            GetMp3Info(m_strFilePath);
            SetWindowTitle(m_strFileName, bPause);
        break;

    case SINGLE_LOOP:
            GetCurrentSelection();
            m_strFilePath =  m_myListCtrl.GetItemText(m_nCurrentSelection,ID_FILEPATH);
            m_strFileName =  m_myListCtrl.GetItemText(m_nCurrentSelection, ID_FILENAME);
            PlayFile(m_strFilePath);
            GetMp3Info(m_strFilePath);
            SetWindowTitle(m_strFileName, bPause);
        break;

    case SINGLE_PLAY:
         mciSendCommand(m_wDeviceID, MCI_STOP, NULL, NULL);
         InitControls();
        break;

    default:
        break;
    }
}
/************************************************************************/
/* 函数名:ConvertTimeToString
/* 参数:时间:time(毫秒为单位), 类型:int
/* 描述:增加歌曲函数,同时在列表框增加文本。                                 */
/************************************************************************/

CString CMyMusicPlayerDlg::ConvertTimeToString(int time)
{
    CString strTmp;
    int nTotalSecond = 0 ;
    int nTotalMinute = 0;

    nTotalSecond = time / 1000; //先将毫秒转换为秒

    if (nTotalSecond < 60)     //如果秒数小于1分钟
    {
        nTotalMinute = 0;
        strTmp.Format(TEXT("%02d:%02d"),nTotalMinute,nTotalSecond);
        return strTmp;
    }
    else {
        nTotalMinute = nTotalSecond / 60;  //得到分钟数
        nTotalSecond = nTotalSecond % 60;  //得到总秒数
        strTmp.Format(TEXT("%02d:%02d"),nTotalMinute,nTotalSecond);
        return strTmp;
    }
}
/************************************************************************/
/* 函数名:GetCurrentSelection
/* 参数:无
/* 描述:获得当前列表控件选中项的位置                                 */
/************************************************************************/
void CMyMusicPlayerDlg::GetCurrentSelection(void)
{
    int nIndexSelection = 0;
    POSITION pos =  m_myListCtrl.GetFirstSelectedItemPosition();     
    nIndexSelection = m_myListCtrl.GetNextSelectedItem(pos); //获得当前播放列表的选中项位置

    m_nCurrentSelection = nIndexSelection;
}
//从文件路径中分析出文件名称(带扩展名)。
int CMyMusicPlayerDlg::ParseFilePath(CString strFilePath)
{
    int nFileNamePos = 0;
    int nFilePathLength = 0;

    m_strFilePath = strFilePath;

    nFileNamePos = strFilePath.ReverseFind(TEXT('\\'));
    nFilePathLength = strFilePath.GetLength();
    m_strFileName = strFilePath.Right(nFilePathLength - nFileNamePos - 1); //从文件路径里分析出文件名
    return 0;
}


//支持键盘加速键并屏蔽Enter键和Esc键关闭对话框
BOOL CMyMusicPlayerDlg::PreTranslateMessage(MSG* pMsg)
{
    if (::TranslateAccelerator(GetSafeHwnd(), hAccel, pMsg))
    {
        return TRUE;
    }

    if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) //屏蔽掉回车键关闭对话框
    {
        return FALSE;
    }

    if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) //屏蔽掉ESC键关闭对话框
    {
        return FALSE;
    }

    return CDialog::PreTranslateMessage(pMsg);
}

//使对话框支持菜单更新命令(Code From MSDN)
void CMyMusicPlayerDlg::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
    ASSERT(pPopupMenu != NULL);  

    CCmdUI state;  
    state.m_pMenu = pPopupMenu;  
    ASSERT(state.m_pOther == NULL);  
    ASSERT(state.m_pParentMenu == NULL);  

    HMENU hParentMenu;  
    if (AfxGetThreadState()->m_hTrackingMenu == pPopupMenu->m_hMenu)  
        state.m_pParentMenu = pPopupMenu;      
    else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)  
    {  
        CWnd* pParent = this;  
        if (pParent != NULL &&  
            (hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)  
        {  
            int nIndexMax = ::GetMenuItemCount(hParentMenu);  
            for (int nIndex = 0; nIndex < nIndexMax; nIndex++)  
            {  
                if (::GetSubMenu(hParentMenu, nIndex) == pPopupMenu->m_hMenu)  
                {  
                    state.m_pParentMenu = CMenu::FromHandle(hParentMenu);  
                    break;  
                }  
            }  
        }  
    }  

    state.m_nIndexMax = pPopupMenu->GetMenuItemCount();  
    for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;  
        state.m_nIndex++)  
    {  
        state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex);  
        if (state.m_nID == 0)  
            continue;   

        ASSERT(state.m_pOther == NULL);  
        ASSERT(state.m_pMenu != NULL);  
        if (state.m_nID == (UINT)-1)  
        {  
            state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex);  
            if (state.m_pSubMenu == NULL ||  
                (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||  
                state.m_nID == (UINT)-1)  
            {  
                continue;        
            }  
            state.DoUpdate(this, TRUE);    
        }  
        else  
        {  
            state.m_pSubMenu = NULL;  
            state.DoUpdate(this, FALSE);  
        }  

        UINT nCount = pPopupMenu->GetMenuItemCount();  
        if (nCount < state.m_nIndexMax)  
        {  
            state.m_nIndex -= (state.m_nIndexMax - nCount);  
            while (state.m_nIndex < nCount &&  
                pPopupMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)  
            {  
                state.m_nIndex++;  
            }  
        }  
        state.m_nIndexMax = nCount;  
    } 

    CDialog::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);

}


/************************************************************************/
/* 函数名:OnTimer
/* 参数:无
/* 描述:使用定时器来更新滑块位置                                 */
/************************************************************************/

void CMyMusicPlayerDlg::OnTimer(UINT_PTR nIDEvent)
{
   // TODO: 在此添加消息处理程序代码和/或调用默认值
   MCI_STATUS_PARMS mciStatus;
   mciStatus.dwItem = MCI_STATUS_POSITION;

   mciSendCommand(m_wDeviceID,MCI_STATUS,MCI_STATUS_ITEM,((DWORD)(LPVOID)&mciStatus));

   dCurrentPos = mciStatus.dwReturn ; //获得当前的播放进度
   m_position.SetPos(dCurrentPos);    //设置播放滑块的位置

   //处理任务栏上的进度显示
   pTaskbar->SetProgressState(this->GetSafeHwnd(), bPause ? TBPF_INDETERMINATE : TBPF_PAUSED);
   pTaskbar->SetProgressValue(this->GetSafeHwnd(), dCurrentPos, m_dLength);

   UpdateCurrentPosText();            //更新并设置当前文件播放时间文本

   if (m_position.GetPos() == m_dLength) //播放结束文件后跳至下个一文件
   {

      SetPlayMode();

   }

   CDialog::OnTimer(nIDEvent);
}

//处理滑块拖动事件
//我花了好大功夫才弄好的
void CMyMusicPlayerDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    if (*pScrollBar == sliderVol)
    {
        int iVol = sliderVol.GetPos();
        SetVolume(iVol);
        CString temp;
        temp.Format(TEXT("%d"),iVol );
        SetDlgItemText(IDC_EDITVOL,temp);
    }

    int iPosition = m_position.GetPos(); //得到slider控件的滑块位置

    MCI_SEEK_PARMS mciSeek; // 
    MCI_PLAY_PARMS mciPlay;

    mciSeek.dwTo = iPosition; //设置跳转后的位置
    mciPlay.dwFrom = mciSeek.dwTo ; //设置播放位置

    mciSendCommand (m_wDeviceID, MCI_SEEK, MCI_TO
        ,(DWORD)(LPVOID)
        &mciSeek);

    mciSendCommand(m_wDeviceID,MCI_PLAY,MCI_FROM | MCI_NOTIFY, (DWORD)(LPVOID)
        &mciPlay);

    m_position.SetPos(mciPlay.dwFrom);
    bPause = TRUE;
    CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}
//对话框支持拖放
void CMyMusicPlayerDlg::OnDropFiles(HDROP hDropInfo)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    int nFileNamePos = 0;
    int nFilePathLength = 0;

    CString m_FilePath; 
    ::DragQueryFile(hDropInfo, 0, m_FilePath.GetBuffer(MAX_PATH), MAX_PATH); 
    m_FilePath.ReleaseBuffer(); 

    nFileNamePos = m_FilePath.ReverseFind(TEXT('\\'));
    nFilePathLength = m_FilePath.GetLength();
    m_strFileName = m_FilePath.Right(nFilePathLength - nFileNamePos - 1); //从文件路径里分析出文件名

    m_strFilePath = m_FilePath;

    PlayFile(m_strFilePath);
    GetMp3Info(m_strFilePath);
    ConvertTimeToString(m_dLength);
    AddFileToPlayList();
    ::DragFinish(hDropInfo);   // 注意这个不能少,它用于释放Windows 为处理文件拖放而分配的内存  
    CDialog::OnDropFiles(hDropInfo);
}

void CMyMusicPlayerDlg::OnClose()
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    KillTimer(ID_PLAYTIMER);
    CDialog::OnClose();
}

//
//每个按钮的逻辑
//

void CMyMusicPlayerDlg::OnBnClickedBtnopen()
{
    if (LoadFile())
    {
         GetCurrentSelection();
        m_myListCtrl.SetItemState(m_nCurrentSelection,LVNI_FOCUSED | LVIS_SELECTED, LVNI_FOCUSED | LVIS_SELECTED);
        pSubPlayMenu->CheckMenuItem(IDM_CONTROL_PLAY, MF_CHECKED);
        PlayFile(m_strFilePath);
        GetMp3Info(m_strFilePath);
        ConvertTimeToString(m_dLength);
        AddFileToPlayList();
    }
    else
    {
        return ;
        // AfxMessageBox(TEXT("你没有打开文件"),MB_ICONINFORMATION,NULL);
    }
}

void CMyMusicPlayerDlg::OnBnClickedBtnpause()
{
    PauseMe();

}

void CMyMusicPlayerDlg::OnBnClickedBtnoprevious()
{
    GoPrevious();
}

void CMyMusicPlayerDlg::OnBnClickedBtnnext()
{
    GoNext();
}

void CMyMusicPlayerDlg::OnBnClickedBtnahead()
{
    GoAhead();
}

void CMyMusicPlayerDlg::OnBnClickedBtnback()
{
    // TODO: 在此添加控件通知处理程序代码
    GoBack();
}

void CMyMusicPlayerDlg::OnBnClickedBtnadd()
{
    if (LoadFile())
    {
        GetCurrentSelection();
        m_myListCtrl.SetItemState(m_nCurrentSelection,LVNI_FOCUSED | LVIS_SELECTED, LVNI_FOCUSED | LVIS_SELECTED);

        m_strTotalLength.Format(TEXT("%02d:%02d"), mp3info.nLength / 60, mp3info.nLength % 60);
        AddFileToPlayList();
    }
    else
    {
        return ;
        // AfxMessageBox(TEXT("你没有打开文件"),MB_ICONINFORMATION,NULL);
    }

}

void CMyMusicPlayerDlg::OnBnClickedBtndelete()
{
    DeleteItem();
}


/************************************************************************/
/* 菜单逻辑                                                                     */
/************************************************************************/
void CMyMusicPlayerDlg::OnFileOpen()
{

    CMyMusicPlayerDlg::OnBnClickedBtnopen();

}
void CMyMusicPlayerDlg::OnFileAddfolder()
{
    // TODO: 在此添加命令处理程序代码
    TCHAR szDisplayName[MAX_PATH] = {0};
    BROWSEINFO bi;
    CString strFindFormat;
    int nCounter = 0;
    CStringArray arrFilePath;
    arrFilePath.SetSize(0, 1);

    ZeroMemory(&bi, sizeof(BROWSEINFO));

    bi.hwndOwner        = this->m_hWnd ;
    bi.iImage           = NULL;
    bi.lParam           = NULL;
    bi.lpfn             = NULL;
    bi.lpszTitle        = TEXT("请选择需要添加的文件夹");
    bi.pidlRoot         = NULL;
    bi.pszDisplayName   = szDisplayName;
    bi.ulFlags          = BIF_NEWDIALOGSTYLE | BIF_DONTGOBELOWDOMAIN  
        | BIF_BROWSEFORCOMPUTER | BIF_RETURNONLYFSDIRS | BIF_RETURNFSANCESTORS;  

    LPITEMIDLIST pIDList = SHBrowseForFolder(&bi);  
    if (pIDList != NULL)  
    {  
        memset(szDisplayName, 0, sizeof(szDisplayName));  
        SHGetPathFromIDList(pIDList, szDisplayName);  
        m_strFilePath = szDisplayName;
    }  
    strFindFormat = m_strFilePath + TEXT("\\*.mp3");

    CFileFind finder;
    BOOL bWorking;
    bWorking = finder.FindFile(strFindFormat);

    while (bWorking)
    {

        bWorking = finder.FindNextFile();
        arrFilePath.SetAtGrow(nCounter, finder.GetFilePath());
        ++nCounter;     

    }

    for (int i = 0; i < nCounter; i++)
    {
        if (PlayFile(arrFilePath[i]))
        {
            ParseFilePath(arrFilePath[i]);
            AddFileToPlayList();
        }
    }
    m_myListCtrl.SetItemState(m_myListCtrl.GetItemCount() - 1 ,LVNI_FOCUSED | LVIS_SELECTED, LVNI_FOCUSED | LVIS_SELECTED);
    m_myListCtrl.EnsureVisible(m_myListCtrl.GetItemCount()-1,FALSE); 
    SetWindowTitle(m_strFileName, bPause);
}


void CMyMusicPlayerDlg::OnAppExit()
{
    SendMessage(WM_CLOSE,0,0);
}

void CMyMusicPlayerDlg::OnHelpAbout()
{
    CAboutDlg aboutdlg;
    aboutdlg.DoModal();
}
void CMyMusicPlayerDlg::OnControlPlay()
{
    bPause = TRUE ;

    MCI_PLAY_PARMS mciPlay;
    mciSendCommand(m_wDeviceID,MCI_PLAY,0,(DWORD)(LPVOID)&mciPlay);

    this->SetWindowText(m_strFileName + TEXT(" 状态:播放"));
    this->SetDlgItemText(IDC_BTNPAUSE,TEXT("暂停"));
    pSubPlayMenu->CheckMenuItem(IDM_CONTROL_PLAY,MF_CHECKED);
    pSubPlayMenu->CheckMenuItem(IDM_CONTROL_PAUSE,MF_UNCHECKED);
}

void CMyMusicPlayerDlg::OnControlPause()
{
    // TODO: 在此添加命令处理程序代码
    PauseMe();
    this->SetDlgItemText(IDC_BTNPAUSE,TEXT("播放"));

    pSubPlayMenu->CheckMenuItem(IDM_CONTROL_PAUSE,MF_CHECKED);
    pSubPlayMenu->CheckMenuItem(IDM_CONTROL_PLAY,MF_UNCHECKED);
}

void CMyMusicPlayerDlg::OnControlPrevious()
{
    // TODO: 在此添加命令处理程序代码
    GoPrevious();
}

void CMyMusicPlayerDlg::OnControlNext()
{
    GoNext();
}

void CMyMusicPlayerDlg::OnControlAhead()
{
    GoAhead();
}

void CMyMusicPlayerDlg::OnControlBack()
{
    GoBack();
}

/************************************************************************/
/* 设置播放模式菜单逻辑                                                                    */
/************************************************************************/

void CMyMusicPlayerDlg::OnModeSequence()
{
    // TODO: 在此添加命令处理程序代码
    m_nPlayMode = SEQUENCE_MODE;
    m_playmode.SetCurSel(SEQUENCE_MODE);
}


void CMyMusicPlayerDlg::OnModeRandom()
{
    // TODO: 在此添加命令处理程序代码
    m_nPlayMode = RANDOM_MODE;
    m_playmode.SetCurSel(RANDOM_MODE);
}


void CMyMusicPlayerDlg::OnModeSingleloop()
{
    // TODO: 在此添加命令处理程序代码
    m_nPlayMode = SINGLE_LOOP;
    m_playmode.SetCurSel(SINGLE_LOOP);
}


void CMyMusicPlayerDlg::OnModeSingleplay()
{
    // TODO: 在此添加命令处理程序代码
    m_nPlayMode = SINGLE_PLAY;
    m_playmode.SetCurSel(SINGLE_PLAY);
}
//播放模式菜单更新逻辑
void CMyMusicPlayerDlg::OnUpdateModeSequence(CCmdUI *pCmdUI)
{
    // TODO: 在此添加命令更新用户界面处理程序代码
    pCmdUI->SetRadio(m_nPlayMode == SEQUENCE_MODE);

}

void CMyMusicPlayerDlg::OnUpdateModeRandom(CCmdUI *pCmdUI)
{
    // TODO: 在此添加命令更新用户界面处理程序代码
    pCmdUI->SetRadio(m_nPlayMode == RANDOM_MODE);
}

void CMyMusicPlayerDlg::OnUpdateModeSingleloop(CCmdUI *pCmdUI)
{
    // TODO: 在此添加命令更新用户界面处理程序代码
        pCmdUI->SetRadio(m_nPlayMode == SINGLE_LOOP);
}

void CMyMusicPlayerDlg::OnUpdateModeSingleplay(CCmdUI *pCmdUI)
{
    // TODO: 在此添加命令更新用户界面处理程序代码
        pCmdUI->SetRadio(m_nPlayMode == SINGLE_PLAY);
}
//播放列表控件菜单项逻辑
void CMyMusicPlayerDlg::OnContextmenuPlayfile()
{
    // TODO: 在此添加命令处理程序代码
    GetCurrentSelection();
    m_strFilePath =  m_myListCtrl.GetItemText(m_nCurrentSelection, ID_FILEPATH);
    PlayFile(m_strFilePath);
}
void CMyMusicPlayerDlg::OnContextmenuPause()
{
    // TODO: 在此添加命令处理程序代码
    PauseMe();
}

void CMyMusicPlayerDlg::OnContextmenuPrevious()
{
    // TODO: 在此添加命令处理程序代码
    GoPrevious();
}

void CMyMusicPlayerDlg::OnContextmenuNext()
{
    // TODO: 在此添加命令处理程序代码
    GoNext();
}

void CMyMusicPlayerDlg::OnContextmenuLoadfile()
{
    // TODO: 在此添加命令处理程序代码
    LoadFile();
    if (!PlayFile(m_strFilePath))
    {
        AfxMessageBox(strMciError);
        return ;
    }
    AddFileToPlayList();
}

void CMyMusicPlayerDlg::OnContextmenuDeleteitem()
{
    // TODO: 在此添加命令处理程序代码
    DeleteItem();
}

//利用Shell来打开文件路径
void CMyMusicPlayerDlg::OnContextmenuOpenfolder()
{
    // TODO: 在此添加命令处理程序代码
    CString strFilePath;
    GetCurrentSelection();
    if (-1 != m_nCurrentSelection)
    {
        strFilePath =  m_myListCtrl.GetItemText(m_nCurrentSelection, ID_FILEPATH);
        strFilePath = TEXT("/select,") + strFilePath;               //select选中此文件
        ::ShellExecute( NULL, _T("open"), _T("explorer.exe"), strFilePath, NULL, SW_SHOWNORMAL );
    }
}

//在列表控件上单击鼠标右键,显示上下文菜单。
void CMyMusicPlayerDlg::OnNMRClickPlaylist(NMHDR *pNMHDR, LRESULT *pResult)
{

    LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    // TODO: 在此添加控件通知处理程序代码
    GetCurrentSelection();
    if (m_nCurrentSelection != -1)
    {
        CMenu menu;
        DWORD dwPos = GetMessagePos();
        CPoint point( LOWORD(dwPos), HIWORD(dwPos) );
        VERIFY( menu.LoadMenu(IDR_CONTEXTMENU));     
        CMenu* popupMenu = menu.GetSubMenu(0);
        if (bPause)
        {
            popupMenu->CheckMenuItem(IDM_CONTEXTMENU_PLAYFILE, MF_CHECKED);
        }
        else
        {
            popupMenu->CheckMenuItem(IDM_CONTEXTMENU_PAUSE, MF_CHECKED);
        }

        ASSERT( popup != NULL );
        popupMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, AfxGetMainWnd()  );
    }
    *pResult = 0;
}
//在列表控件上双击某个项目
void CMyMusicPlayerDlg::OnNMDblclkPlaylist(NMHDR *pNMHDR, LRESULT *pResult)
{

    LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    // TODO: 在此添加控件通知处理程序代码
    GetCurrentSelection();

    if (-1 != m_nCurrentSelection)
    {
        m_strFileName =  m_myListCtrl.GetItemText(m_nCurrentSelection, ID_FILENAME);
        m_strFilePath =  m_myListCtrl.GetItemText(m_nCurrentSelection, ID_FILEPATH);

        GetMp3Info(m_strFilePath);
        PlayFile(m_strFilePath);    
        SetWindowTitle(m_strFileName, bPause);
    }
    *pResult = 0;
}
//在列表控件上单击项目可以显示音频文件的tag信息
void CMyMusicPlayerDlg::OnNMClickPlaylist(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    // TODO: 在此添加控件通知处理程序代码
    GetCurrentSelection();

    if (-1 != m_nCurrentSelection)
    {
        m_strFileName =  m_myListCtrl.GetItemText(m_nCurrentSelection, ID_FILENAME);
        m_strFilePath =  m_myListCtrl.GetItemText(m_nCurrentSelection, ID_FILEPATH);
        GetMp3Info(m_strFilePath);
    }
    *pResult = 0;
}
//播放模式组合框内容变化
void CMyMusicPlayerDlg::OnCbnSelchangeComplaymode()
{
    int nIndex = m_playmode.GetCurSel();
    m_nPlayMode = nIndex;
}
//列表控件项目变化
void CMyMusicPlayerDlg::OnLvnItemchangedPlaylist(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
    // TODO: 在此添加控件通知处理程序代码
    CString str;
    int nCounter;

    nCounter = m_myListCtrl.GetItemCount();
    str.Format(TEXT("播放列表(歌曲数目: %d)"),nCounter);

    GetDlgItem(IDC_GROUPPLAYLIST)->SetWindowText(str);

    *pResult = 0;
}

AboutDlg的头文件(打开关于对话框)

#pragma once
#include "afxcmn.h"


// CAboutDlg 对话框

class CAboutDlg : public CDialog
{
    DECLARE_DYNAMIC(CAboutDlg)

public:
    CAboutDlg(CWnd* pParent = NULL);   // 标准构造函数
    virtual ~CAboutDlg();

// 对话框数据
    enum { IDD = IDD_ABOUTBOX };

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

    DECLARE_MESSAGE_MAP()

public:
    afx_msg void OnNMClickSyslink(NMHDR *pNMHDR, LRESULT *pResult);
};

AboutDlg的实现文件

// AboutDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "My Music Player.h"
#include "AboutDlg.h"
#include "afxdialogex.h"


// CAboutDlg 对话框

IMPLEMENT_DYNAMIC(CAboutDlg, CDialog)

CAboutDlg::CAboutDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CAboutDlg::IDD, pParent)
{

}

CAboutDlg::~CAboutDlg()
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);

}


BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
    ON_NOTIFY(NM_CLICK, IDC_SYSLINK, &CAboutDlg::OnNMClickSyslink)
END_MESSAGE_MAP()


// CAboutDlg 消息处理程序



void CAboutDlg::OnNMClickSyslink(NMHDR *pNMHDR, LRESULT *pResult)
{
    // TODO: 在此添加控件通知处理程序代码
    PNMLINK pNMLink = (PNMLINK) pNMHDR;  
    // 打开我的博客
    ::ShellExecute(GetSafeHwnd(), _T("open"), pNMLink->item.szUrl, NULL, NULL, SW_SHOWNORMAL);
    *pResult = 0;
}

resource头文件(资源)

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by My Music Player.rc
//
#define IDM_ABOUTBOX                    0x0010
#define IDD_ABOUTBOX                    100
#define IDS_ABOUTBOX                    101
#define IDD_MYMUSICPLAYER_DIALOG        102
#define IDR_MENU1                       130
#define IDR_MAINFRAME                   130
#define IDR_ACCELERATOR1                134
#define IDI_ICON1                       135
#define IDR_CONTEXTMENU                 137
#define IDD_DIALOG1                     138
#define IDC_SLIDER1                     1000
#define IDC_SLIDERPOS                   1000
#define IDC_PLAYLIST                    1003
#define IDC_BTNOPEN                     1004
#define IDC_BUTTON2                     1005
#define IDC_BTNEXIT                     1005
#define IDC_BTNPAUSE                    1006
#define IDC_SLIDERVOL                   1007
#define IDC_BTNOPREVIOUS                1009
#define IDC_BTNPREVIOUS                 1009
#define IDC_BTNNEXT                     1010
#define IDC_BTNDELETE                   1011
#define IDC_BTNAHEAD                    1012
#define IDC_BTNBACK                     1013
#define IDC_BTNADD                      1014
#define IDC_BTNSTOP                     1015
#define IDC_CURPOS                      1016
#define IDC_TOTAL_LENGTH                1016
#define IDC_EDIT2                       1017
#define IDC_CURRENT_POS                 1017
#define IDC_EDIT3                       1018
#define IDC_EDITVOL                     1018
#define IDC_COMPLAYMODE                 1021
#define IDC_MFCLINK1                    1022
#define IDC_EDIT_SONGTITLE              1023
#define IDC_EDIT_ARTIST                 1024
#define IDC_EDIT_ALB                    1025
#define IDC_EDIT_ALBUM                  1025
#define IDC_EDIT_ARTIST2                1026
#define IDC_EDIT_YEAR                   1026
#define IDC_SYSLINK1                    1028
#define IDC_SYSLINK                     1028
#define IDC_PROGRESS1                   1029
#define IDC_EDIT1                       1030
#define IDC_EDIT_SONGCOUNTER            1030
#define IDC_EDIT_SONGBITRATE            1031
#define IDC_EDIT_GENRE                  1032
#define IDC_GROUPSONG                   1033
#define IDC_GROUPPLAYLIST               1033
#define ID_32771                        32771
#define ID_32772                        32772
#define IDM_FILE_OPEN                   32773
#define IDM_APP_EXIT                    32774
#define ID_32775                        32775
#define IDM_HELP_ABOUT                  32776
#define ID_32777                        32777
#define ID_Menu                         32778
#define ID_32779                        32779
#define ID_32780                        32780
#define ID_32781                        32781
#define IDM_CONTROL_PLAY                32782
#define IDM_CONTROL_PAUSE               32783
#define IDM_CONTROL_STOP                32784
#define IDM_CONTROL_AHEAD               32785
#define IDM_CONTROL_BACK                32786
#define ID_32787                        32787
#define ID_32788                        32788
#define IDM_CONTROL_PREVIOUS            32793
#define IDM_CONTROL_NEXT                32794
#define ID_32802                        32802
#define ID_32803                        32803
#define ID_32804                        32804
#define ID_32805                        32805
#define ID_MODE_SEQUENCE                32806
#define ID_MODE_RANDOM                  32807
#define ID_MODE_SINGLELOOP              32808
#define ID_MODE_SINGLEPLAY              32809
#define ID__32810                       32810
#define ID__32811                       32811
#define ID__32812                       32812
#define IDM_OPENFOLDER                  32813
#define IDM_DELETECURITEM               32814
#define ID__32815                       32815
#define ID__32816                       32816
#define ID__32817                       32817
#define ID__32818                       32818
#define IDM_PLAYFILE                    32819
#define IDM_GONEXT                      32820
#define IDM_                            32821
#define IDM_GOPREVIOUS                  32822
#define ID__ADDFILE                     32823
#define ID__DELETEITEM                  32824
#define IDM__ADDFILE                    32825
#define IDM__DELETEITEM                 32826
#define IDM__LOADFILE                   32827
#define IDM_DELETEITEM                  32828
#define IDM_LOADFILE                    32829
#define IDM_PAUSE                       32830
#define ID_Menu32831                    32831
#define IDM_PREVIOUS                    32832
#define ID_32833                        32833
#define IDM_NEXT                        32834
#define IDM_CONTEXTMENU_PLAYFILE        32835
#define IDM_CONTEXTMENU_PAUSE           32836
#define IDM_CONTEXTMENU_PREVIOUS        32837
#define IDM_CONTEXTMENU_NEXT            32838
#define IDM_CONTEXTMENU_LOADFILE        32839
#define IDM_CONTEXTMENU_DELETEITEM      32840
#define IDM_CONTEXTMENU_OPENFOLDER      32841
#define ID_32842                        32842
#define ID_32843                        32843
#define IDM_FILE_ADDFOLDER              32844

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        139
#define _APS_NEXT_COMMAND_VALUE         32847
#define _APS_NEXT_CONTROL_VALUE         1034
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

targetver 头文件


#pragma once

// 以下宏定义要求的最低平台。要求的最低平台
// 是具有运行应用程序所需功能的 Windows、Internet Explorer 等产品的
// 最早版本。通过在指定版本及更低版本的平台上启用所有可用的功能,宏可以
// 正常工作。

// 如果必须要针对低于以下指定版本的平台,请修改下列定义。
// 有关不同平台对应值的最新信息,请参考 MSDN。
#ifndef WINVER                          // 指定要求的最低平台是 Windows Vista。
#define WINVER 0x0600           // 将此值更改为相应的值,以适用于 Windows 的其他版本。
#endif

#ifndef _WIN32_WINNT            // 指定要求的最低平台是 Windows Vista。
#define _WIN32_WINNT 0x0600     // 将此值更改为相应的值,以适用于 Windows 的其他版本。
#endif

#ifndef _WIN32_WINDOWS          // 指定要求的最低平台是 Windows 98。
#define _WIN32_WINDOWS 0x0410 // 将此值更改为适当的值,以适用于 Windows Me 或更高版本。
#endif

#ifndef _WIN32_IE                       // 指定要求的最低平台是 Internet Explorer 7.0。
#define _WIN32_IE 0x0700        // 将此值更改为相应的值,以适用于 IE 的其他版本。
#endif

完整项目请到此处下载:
http://download.csdn.net/detail/codemore/9423741

  • 14
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值