上一章中,主要是介紹了WINDOWS訊息機制和模板對話方塊的建立,其實學到現在感覺windows程式設計就是各種邏輯+API函式。所以MSDN很重要。由於整個程式碼太大了,所以下面系列文章中,我只講思路以及一些控制元件的用法。原始碼以後會上傳。請大家多多支援...
下面先上個 最後的效果圖..
這節主要總結下最核心的播放功能,如何實現的。只提供關鍵思路。
核心思路:
1.按“新增”按鈕,將新增歌曲進入Listbox。具有數字標號+歌曲名字
這裡包括檔案新增的操作,listBox的插入操作,字串函式的操作
2.雙擊Listbox中某個歌曲將可以播放,並且可以有時間進度條和總時間
這裡包括 listbox響應雙擊事件,mcisendCommand和關聯結構體操作
1.新增檔案的操作
在開始播放前,肯定要手動新增哪些要加入到播放列表中,就是上面按鈕"新增"觸發的操作。這裡涉及檔案的開啟以及多個檔案同時選中的情況。關鍵程式碼如下:
void DoSelectFile(HWND hwnd) //選擇檔案
{
OPENFILENAME ofn; //定義一個檔案結構體
TCHAR szOpenFileNames[80*MAX_PATH]; //開啟的檔名字
TCHAR szPath[MAX_PATH]; //歌曲檔案的路徑 其實操作一個Mp3檔案就是通過路徑來操作的
TCHAR szFileName[80*MAX_PATH];
ZeroMemory(szOpenFileNames,sizeof(szOpenFileNames)/sizeof(TCHAR));
ZeroMemory(&ofn,sizeof(ofn));
ZeroMemory(szFileName,sizeof(szFileName));
ZeroMemory(szPath,sizeof(szPath)); //清空 各類結構
//配置ofn各欄位
ofn.Flags=OFN_EXPLORER|OFN_ALLOWMULTISELECT;//指定瀏覽功能,和允許多選功能
ofn.hwndOwner=hwnd; //父控制程式碼為當前對話方塊
ofn.lStructSize=sizeof(ofn);//整個ofn結構體的大小 (這裡以前犯了個錯誤&ofn)
ofn.lpstrFile=szOpenFileNames;//開啟的檔案的全路徑
ofn.nMaxFile=sizeof(szOpenFileNames);//檔案大小的最大值
ofn.lpstrFile[0]='\0';//指定第一個為NULL字元
ofn.lpstrFilter=TEXT("*.mp3\0*.mp3\0*.wav\0*.wav\0All files\0*.*\0");//檔案過濾器
if(GetOpenFileName(&ofn)) //成功返回非零 不成功為0
{
TCHAR withnum_song[255];//帶數字列表的 插入到listbox的歌曲名
ZeroMemory(withnum_song,sizeof(withnum_song)/sizeof(TCHAR));
lstrcpyn(szPath,szOpenFileNames,ofn.nFileOffset);//獲取該多個檔案所在的目錄 單個檔案不需要加‘\’,多個檔案少個\
if(szPath[lstrlen(szPath)-1]!='\\')
{
lstrcat(szPath,TEXT("\\")); //這裡又要犯錯誤了,lstrcat是連線兩個字串,\在字串中必須是"\\"
}
// MessageBox(hwnd,szPath,TEXT("szPath2"),MB_OK);
TCHAR *p=szOpenFileNames+ofn.nFileOffset;//get the first file name
while(*p)
{
lstrcpy(fileinfo[isong].songname,p); // 儲存歌曲名 歌曲複製到 全域性檔案資訊庫
lstrcpy(szFileName,szPath);
lstrcat(szFileName,p);
lstrcpy(fileinfo[isong].szfiledir,szFileName); //儲存歌曲完整路徑
TCHAR puresn[255]; //純的songname=sn
ZeroMemory(puresn,sizeof(puresn)/sizeof(TCHAR));
TCHAR *pos=strrchr(p,'.');//從後往前查詢'.' .mp3的.
lstrcpyn(puresn,p,pos-p+1);
ZeroMemory(withnum_song,sizeof(withnum_song)/sizeof(TCHAR));
wsprintf(withnum_song,TEXT("%02d %s"),isong+1,puresn);
ListBox_InsertString(hlistbox,-1,withnum_song);
p=p+lstrlen(p)+1; //移動到下一個檔名
ZeroMemory(szFileName,sizeof(szFileName));
isong++; //歌曲自加1
}
}
}
上面就是檔案的操作了,包括歌曲的新增和 往ListBox中插入歌曲名字。其實全部都是檔案路徑的操作,我們要得到歌曲的路徑,存於全域性變數中 我這裡是存到一個全域性結構體中,用來存放歌曲名字和路徑 。
typedef struct //defined a information struct for song
{
TCHAR songname[50]; //注意這個值過小 可能導致 輸入的資訊有誤,要保證有絕對空間 查了半天的錯
TCHAR szfiledir[100];
}FileInfo;
FileInfo fileinfo[255]; //檔案資訊 只能存255首歌曲
歌曲的名字,我們希望有標號,並且希望歌曲名字不帶.mp3的字樣,這裡就是擷取的方法,利用字串函式的操作,來獲取我們想要的檔名字。當我們同時選取了多個檔案時,實際上在記憶體中存在的形式就是該檔案的目錄+各個檔名字,每個檔名字以一個'\0'隔開。在呼叫完(GetOpenFileName(&ofn)這個函式成功後,會將你選擇的檔名全部存於該 ofn.lpstrFile=szOpenFileNames.也就是存於szOpenFileNames的陣列中。
所以剩下要做兩件事: 1.獲取每首歌曲完整路徑 2.拼寫出每個歌曲的名字
將獲取的名字 格式化 加上數字,就插入到Listbox中即可。具體的參見工程中的程式碼。
2.播放音樂
在上面我們大概瞭解了這麼新增檔案和修改檔名,剩下的就是要播放了,其實要播放一首歌曲很簡單,只需要條用mciSendCommand().函式即可,比如下面程式碼就可以播放一首歌曲
mciSendCommand(DeviceId,MCI_PLAY,MCI_FROM|MCI_NOTIFY,(DWORD)(LPVOID)&mciplay);
引數1:是要播放的裝置號 引數2:是要播放的命令,引數3:是從哪裡播放和播放完傳送給主視窗一個通知
引數4:是結構體。每個mcisendcommand 都要關聯一個結構體,這要關聯播放mciplay
MCIDEVICEID DeviceId=0; //開啟的裝置ID號
MCI_OPEN_PARMS mciopen; //開啟結構體
MCI_PLAY_PARMS mciplay; //播放結構體
MCI_SET_PARMS mciset; //設定時間格式
MCI_SEEK_PARMS mciseek; // 設定跳轉到
MCI_STATUS_PARMS mcistatus; //播放狀態 獲得歌曲總長度
具體的意思 和怎麼使用查詢 MSDN手冊。
思路:就是先配置 mciopen。指定開啟的路徑(就是音樂檔案的路徑)成功開啟後,得到一個裝置號,然後用該裝置號來操作,比如播放,暫停,關閉..附加的功能 比如獲取 歌曲狀態,得到歌曲的總時間。
下面程式碼演示了怎麼開啟裝置和獲取歌曲總時間長度
BOOL DoPlay(HWND hwnd,INT index)
{
mciopen.lpstrElementName=fileinfo[index].szfiledir; //給開啟裝置指定路徑
mciSendCommand(DeviceId,MCI_STOP,0,0);
mciSendCommand(DeviceId,MCI_CLOSE,0,0); //先關閉全部變數的裝置
if(0==mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_ELEMENT,(DWORD)(LPVOID)&mciopen)) //成功返回為0
{
// MessageBox(hwnd,TEXT("MCIOPEN開啟裝置成功"),TEXT(""),MB_OK);
DeviceId=mciopen.wDeviceID;//成功開啟後將ID號保留下來。
mciset.dwTimeFormat=MCI_FORMAT_MILLISECONDS; //config mciset time format
mciSendCommand(DeviceId,MCI_SET,MCI_WAIT|MCI_FORMAT_MILLISECONDS,(DWORD)(LPMCI_SET_PARMS)&mciset);//設定歌曲的長度以Ms度量
mcistatus.dwItem=MCI_STATUS_LENGTH;
mciSendCommand(DeviceId,MCI_STATUS,MCI_WAIT|MCI_STATUS_ITEM,(DWORD)(LPMCI_STATUS_PARMS)&mcistatus);
DWORD dwsonglen=mcistatus.dwReturn/1000; //返回歌曲的總長度 ms級別的 dwsonglen單位是秒
SendDlgItemMessage(hwnd,IDC_SLIDER_SONG,TBM_SETRANGE,TRUE,MAKELPARAM(0,dwsonglen));//設定Silder的兩端範圍
mciplay.dwFrom=0;//從0開始播放
mciplay.dwCallback=(DWORD)hwnd;//播放完畢後,通該視窗處理函式
mciSendCommand(DeviceId,MCI_PLAY,MCI_FROM|MCI_NOTIFY,(DWORD)(LPVOID)&mciplay);//開始播放
ListBox_SetCurSel(hlistbox,iIndex); //設定當前選中巨集
return TRUE;
}
else
MessageBox(hwnd,TEXT("開啟歌曲錯誤"),TEXT("errror!"),MB_OK);
return FALSE;
}
下個模組繼續...