MCI音樂播放

原因:

  在改正俄羅斯方塊程序的功能的時候,想給這個程序增長一個背景音樂。本想用PlayWave來作的,但想到這個功能十分經常使用,那還不如封裝一個本身的CMusicios

類,以備不時之需。原本覺得很容易的,但是在真正操做的時候,卻出現了一個問題,就是沒法準確的知道何時音樂播放完成。問題的難道就在於,怎樣將類的成員函數做爲窗口的回調函數。windows

 本來用thunk來解決這個問題的,可是在解決的時候出現了一個問題,調試了好幾天都沒有解決。直到最近才解決。(也就是前一篇文章的由來)ide

代碼:(前面定義的宏主要是解決Unicode問題)

cMusic.h函數

複製代碼
  1 #ifndef CMUSIC_H  2 #define CMUSIC_H  3  4 #ifdef _UNICODE  5 #define tstring wstring  6 #define tcout wcout  7 #define tcin wcin  8 #else  9 #define tstring string  10 #define tcout cout  11 #define tcin cin  12  13 #endif  14  15 #pragma warning(disable:4311)  16  17 #include "TCHAR.h"  18 #include<iostream>  19 #include<windows.h>  20 #include<string>  21 #include<vector>  22 #include<MMSystem.h>  23 #pragma comment(lib,"Winmm.lib")  24 using namespace std;  25  26 typedef LRESULT (*pfaCallBack)(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);  27 #pragma pack(push,1)  28 struct Thunk  29 {  30  BYTE op_movecx;  31  DWORD_PTR val_ecx;  32  BYTE op_call;  33  DWORD_PTR val_address;  34 };  35 #pragma pack(pop)  36  37 #define MY_WM_PLAY WM_USER+1  38 #define MY_WM_PAUSE WM_USER+2  39 #define MY_WM_STOP WM_USER+3  40 #define MY_WM_CLOSE WM_USER+4  41 #define MY_WM_PLAYNEXT WM_USER+5  42 #define MY_WM_PLAYLAST WM_USER+6  43 #define MY_WM_REPLAY WM_USER+7  44 #define MY_WM_PLAY_LOOP WM_USER+8  45 #define MY_WM_RESUME WM_USER+9  46 #define MY_WM_TEST0 WM_USER+10  47  48 //類說明開始  49 //=========================================================//  50 // 功能:播放音樂以及進行相關的控制  51 // 設計思路:  52 // 這個類的實現應該會比較簡單,主要是利用MCI開頭的函數來進行控制  53 // 最主要實現一下功能:  54 // 播放一個音頻文件  55 // 暫停播放  56 // 恢復播放  57 // 獲得音頻文件的信息  58 // 文件名  59 // 長度  60 // 當前播放的位置  61 // 顯示播放列表//一個文件夾中的全部MP3或者是wav文件  62 // 播放上一首  63 // 播放下一首  64 //  65 // 做者:張敏  66 // 日期:2013-1-10 郵箱 zhang19min88@163.com  67 // 注意:實現這個類個人最大的感想就是不要想在一個類中封裝全部的函數  68 // 在真正要用的時候再進行繼承  69 //也許這樣不會焦頭亂額  70 //=========================================================//  71 class ZMCMusic  72 {  73 public:  74  friend DWORD WINAPI ThreadProc(LPVOID);  75 public:  76 ZMCMusic();//構造函數  77 ~ZMCMusic();//析構函數  78 public:  79 void Init();  80 void AddPlayList(tstring tstrDir);  81  BOOL Play();  82  BOOL Pause();  83  BOOL Resume();  84  BOOL Stop();  85  BOOL Close();  86  BOOL Replay();  87 BOOL PlayNext();//播放下一曲  88 BOOL playLast();//播放上一曲  89  BOOL GetFileInfo();  90 BOOL LoadMusicFile(tstring const tstrFileNmae);  91 static void ShowError();  92 private:  93 void GetCurPos();  94 void GetFileLenth();  95 int MakeWindow();//產生一個窗口  96 int CreateWindowInThread();//在線程中建立窗口  97 LRESULT ProcWindow(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);//窗口過程的處理函數  98 private:  99  tstring m_tstrFileName; 100 vector<tstring> m_vcPlayList;//保存播放列表 101 int m_nCurPlayIndex;//當前正在播放文件夾的索引 102 int m_nFileLen;//文件的總長度 103 int m_nCurPos;//當前正播放的位置 104 int m_nSound;//播放的音量大小 105 private: 106  HWND m_hWnd; 107  HANDLE m_hThread; 108  HINSTANCE m_hInstance; 109  UINT m_uDeviceID; 110  DWORD m_dwThreadID; 111  tstring m_tstrWinClassName; 112  tstring m_tstrWinCaptionName; 113 private: 114 void InitThunk() 115  { 116 m_thunk.op_movecx=0xB9;// 0xb9 mov ecx,數值的 機器碼 117 m_thunk.val_ecx=(DWORD_PTR)this; 118 m_thunk.op_call=0xE9;//0xe9是Jmp 相對地址的機器碼 119 DWORD_PTR off=0; 120  _asm 121  { 122  mov eax,ZMCMusic::ProcWindow 123  mov DWORD PTR[off],eax 124  } 125 m_thunk.val_address=off-((DWORD_PTR)(&m_thunk.val_address)+sizeof(DWORD_PTR)); 126  } 127  pfaCallBack GetStaticEntry() 128  { 129 return (pfaCallBack)&m_thunk; 130  } 131 private: 132  Thunk m_thunk; 133 }; 134 135 #endif
複製代碼

cMusic.cppthis

複製代碼
  1 #include "cMusic.h"  2 //程序說明開始  3 //=========================================================//  4 // 功能:類的構造函數,因爲本類須要 建立一個隱藏的窗口,用來接收  5 // 播放完成以後的消息。因此在構造類的時候,很天然也須要構建一個  6 // 隱藏的窗口  7 // 參數:無  8 // 返回 :無  9 // 主要思路:  10 // 初始化一些變量 而且調用createThread函數建立一個線程,而且在線程中  11 // 建立一個窗口  12 // 調用方法:系統自動調用  13 // 做者:張敏  14 // 日期:2012-1-11 郵箱 zhang19min88@163.com  15 // 說明:  16 //=========================================================//  17 ZMCMusic::ZMCMusic()  18 {  19 m_uDeviceID=0;  20 m_tstrFileName=_T("");  21 m_tstrWinCaptionName=_T("MCI");  22 m_tstrWinClassName=_T("CMCI");  23 m_nSound=0;  24 m_nFileLen=0;  25 m_nCurPos=0;  26 m_dwThreadID=0;  27 m_nCurPlayIndex=0;  28 m_hInstance=(HINSTANCE)GetModuleHandle(NULL);  29  InitThunk();  30 }  31 void ZMCMusic::Init()  32 {  33 CreateWindowInThread();//在線程中建立一個窗口  34 }  35 ZMCMusic::~ZMCMusic()  36 {  37  38 }  39 //程序說明開始  40 //=========================================================//  41 // 功能:加載須要播放的文件  42 // 參數:tstrFileName 須要加載的文件名  43 // 返回 :成功執行返回真 不然返回假  44 // 主要思路:  45 // 調用MCISendCommand函數 發送MCI_OPEN命令  46 // 獲得一個設備ID  47 // 調用方法:外部接口函數  48 // 做者:張敏  49 // 日期:2013-1-10 郵箱 zhang19min88@163.com  50 // 說明:  51 //=========================================================//  52 BOOL ZMCMusic::LoadMusicFile(tstring const tstrFileNmae)  53 {  54 m_tstrFileName=tstrFileNmae;  55  MCI_OPEN_PARMS mciOPenParms;  56 DWORD dwReturn=0;  57  58 mciOPenParms.lpstrDeviceType=_T("mpegvideo");//使用這種類型,能夠播放MP3  59 mciOPenParms.lpstrElementName=m_tstrFileName.c_str();//也就是播放的音頻文件的路徑名  60 mciOPenParms.dwCallback=(DWORD_PTR)m_hWnd;//該命令成功執行後 想m_hWnd窗口發送一條消息  61  62 dwReturn=mciSendCommand(0,MCI_OPEN,MCI_OPEN_TYPE|MCI_OPEN_ELEMENT,(DWORD)(LPVOID)&mciOPenParms);  63 if(dwReturn!=0)  64  {  65 return FALSE;  66 }//成功打開這個設備  67 m_uDeviceID=mciOPenParms.wDeviceID; //獲得一個設備的ID號  68  69 //MCI_STATUS_PARMS mciStatusParms;  70 //ZeroMemory(&mciStatusParms,sizeof(mciStatusParms));  71 //mciStatusParms.dwItem=MCI_STATUS_LENGTH;  72 //if(mciSendCommand( m_uDeviceID , MCI_STATUS , MCI_STATUS_ITEM , (DWORD)(LPMCI_STATUS_PARMS) &mciStatusParms )==0 )  73 //{  74 // m_nFileLen=mciStatusParms.dwReturn;  75 //}  76 return TRUE;  77 }  78  79 //程序說明開始  80 //=========================================================//  81 // 功能:播放加載了的音頻文件  82 // 參數:  83 // 返回 :成功執行返回真 不然返回假  84 // 主要思路:  85 // 調用MCISendCommand函數 發送MCI_PLAY命令  86 // 調用方法:外部接口函數  87 // 做者:張敏  88 // 日期:2013-2-26 郵箱 zhang19min88@163.com  89 // 說明:  90 // 在這裏並有處理MCI_NOTIFY消息,經過這個消息咱們能夠知道播放是否結束  91 // 當歌曲播放完成以後 咱們會收到一個播放完成的消息  92 //=========================================================//  93 BOOL ZMCMusic::Play()  94 {  95 //LoadMusicFile(m_vcPlayList[ m_nCurPlayIndex]);  96  MCI_PLAY_PARMS mciPlayParms;  97 ZeroMemory(&mciPlayParms,sizeof(mciPlayParms));  98 mciPlayParms.dwCallback=(DWORD)m_hWnd;  99 return mciSendCommand(m_uDeviceID,MCI_PLAY,MCI_NOTIFY,(DWORD)(LPVOID)&mciPlayParms); 100 } 101 //程序說明開始 102 //=========================================================// 103 // 功能:暫停當前播放的文件 104 // 參數:無 105 // 返回 :成功執行返回真 不然返回假 106 // 主要思路: 107 // 調用MCISendCommand函數 發送MCI_PAUSE命令 108 // 調用方法:外部接口函數 109 // 做者:張敏 110 // 日期:2012-1-10 郵箱 zhang19min88@163.com 111 // 說明: 112 // 在這裏並無處理MCI_NOTIFY消息,經過這個消息咱們能夠知道播放是否結束 113 //=========================================================// 114 BOOL ZMCMusic::Pause() 115 { 116  MCI_GENERIC_PARMS mciGenericParms; 117 ZeroMemory(&mciGenericParms,sizeof(mciGenericParms)); 118 mciGenericParms.dwCallback=(DWORD_PTR)m_hWnd; 119 return mciSendCommand(m_uDeviceID,MCI_PAUSE,MCI_WAIT,(DWORD)(LPVOID)&mciGenericParms); 120 } 121 //程序說明開始 122 //=========================================================// 123 // 功能:繼續播放當前被暫停播放的文件 124 // 參數:無 125 // 返回 :成功執行返回真 不然返回假 126 // 主要思路: 127 // 調用MCISendCommand函數 發送MCI_RESUME命令 128 // 調用方法:外部接口函數 129 // 做者:張敏 130 // 日期:2012-1-10 郵箱 zhang19min88@163.com 131 // 說明: 132 // 133 //=========================================================// 134 BOOL ZMCMusic::Resume() 135 { 136  MCI_GENERIC_PARMS mciGenericParms; 137 ZeroMemory(&mciGenericParms,sizeof(mciGenericParms)); 138 return mciSendCommand(m_uDeviceID,MCI_RESUME,MCI_NOTIFY,(DWORD)(LPVOID)&mciGenericParms); 139 } 140 //程序說明開始 141 //=========================================================// 142 // 功能:中止播放的文件 143 // 參數:無 144 // 返回 :成功執行返回真 不然返回假 145 // 主要思路: 146 // 調用MCISendCommand函數 發送MCI_STOP命令 147 // 調用方法:外部接口函數 148 // 做者:張敏 149 // 日期:2012-1-10 郵箱 zhang19min88@163.com 150 // 說明: 151 // 這個命令和PAUSE是不一樣的 pause只是暫停播放,但播放的內容依然在內存中,能夠繼續播放 152 // 而STOP則是該文件退出資源 不能繼續播放 153 //對於這個命令的確切理解MSDN上說 它和Pause的區別是看不一樣的設備來講的 154 //=========================================================// 155 BOOL ZMCMusic::Stop() 156 { 157 return mciSendCommand(m_uDeviceID,MCI_STOP,NULL,NULL); 158 } 159 //程序說明開始 160 //=========================================================// 161 // 功能:關閉播放設備 162 // 參數:無 163 // 返回 :成功執行返回真 不然返回假 164 // 主要思路: 165 // 調用MCISendCommand函數 發送MCI_CLOSE命令 166 // 調用方法:外部接口函數 167 // 做者:張敏 168 // 日期:2013-1-11 郵箱 zhang19min88@163.com 169 // 說明: 170 // 這個命令和PAUSE是不一樣的 pause只是暫停播放,但播放的內容依然在內存中,能夠繼續播放 171 // 而STOP則是該文件退出資源 不能繼續播放 172 //=========================================================// 173 BOOL ZMCMusic::Close() 174 { 175 return mciSendCommand(m_uDeviceID,MCI_CLOSE,NULL,NULL); 176 } 177 //程序說明開始 178 //=========================================================// 179 // 功能:從新播放 180 // 參數:無 181 // 返回 :成功執行返回真 不然返回假 182 // 主要思路: 183 // 調用CLose()函數 關閉設備 而後調用LoadMusicFile()函數打開設備 最後調用Play()函數進行播放 184 // 調用方法:外部接口函數 185 // 做者:張敏 186 // 日期:2013-2-27 郵箱 zhang19min88@163.com 187 // 說明: 188 //=========================================================// 189 BOOL ZMCMusic::Replay() 190 { 191  Close(); 192  LoadMusicFile(m_tstrFileName); 193 return Play(); 194 } 195 196 197 198 int ZMCMusic::MakeWindow() 199 { 200  MSG stMsg; 201 TCHAR szClassName[]=_T("MCI"); 202 203  WNDCLASSEX stWC; 204 ZeroMemory(&stWC,sizeof(stWC)); 205 stWC.hCursor=LoadCursor(NULL,IDC_ARROW); 206 stWC.cbSize=sizeof(stWC); 207 stWC.style=CS_HREDRAW|CS_VREDRAW; 208 stWC.lpfnWndProc=(WNDPROC)ZMCMusic::GetStaticEntry();//將類成員函數做爲窗口過程函數 209 //stWC.lpfnWndProc=DefWindowProc; 210 stWC.lpszClassName=m_tstrWinClassName.c_str(); 211 stWC.cbClsExtra=0; 212 stWC.hInstance=m_hInstance; 213 214 RegisterClassEx(&stWC); 215 216 m_hWnd=CreateWindowEx(WS_EX_CLIENTEDGE,m_tstrWinClassName.c_str(),m_tstrWinCaptionName.c_str(),WS_OVERLAPPEDWINDOW,100,100,600,700,NULL,NULL,m_hInstance,NULL); 217 if(m_hWnd==NULL) 218  { 219  ShowError(); 220  } 221  ShowWindow(m_hWnd,SW_HIDE); 222  UpdateWindow(m_hWnd); 223 while(GetMessage(&stMsg,NULL,0,0)) 224  { 225 TranslateMessage(&stMsg); 226 DispatchMessage(&stMsg); 227  } 228 return 0 ; 229 } 230 231 //程序說明開始 232 //=========================================================// 233 // 功能:窗口過程的處理函數 234 // 參數:hWNd uMsg wParam lParam 正常窗口回調函數 235 // 返回 :無 236 // 主要思路: 237 // 在這個回調函數中咱們完成的就是處理MM_MCINOTIFY消息,主要是對MCI播放命令的執行結果進行響應 238 // 最關鍵的一個結果是經過這個消息的處理咱們能夠知道何時音樂播放完成 239 // 調用方法:系統自動調用 240 // 做者:張敏 241 // 日期:2012-1-11 郵箱 zhang19min88@163.com 242 // 說明: 243 //=========================================================// 244 245 //這個類該怎樣利用還不是很清楚 246 LRESULT ZMCMusic::ProcWindow(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) 247 { 248 switch(uMsg) 249  { 250 case WM_CREATE: 251 // MessageBox(NULL,_T("MCI"),_T("MCI"),MB_OK); 252 break; 253 case MM_MCINOTIFY://當播放完成以後 254 //在這裏能夠進行不少設置 255 //比喻說設定單曲循環 256 //設置自動播放下一首等等 257 //關鍵是如何用代碼進行封裝 258 //MessageBox(NULL,_T("MCI"),_T("Play End!"),MB_OK); 259 this->Replay(); 260 break; 261 case MY_WM_PLAY: break; 262 case MY_WM_PAUSE:break; 263 case MY_WM_STOP:break; 264 case MY_WM_RESUME:break; 265 case MY_WM_REPLAY:break; 266 case MY_WM_PLAYNEXT:break; 267 case MY_WM_PLAYLAST:break; 268 case MY_WM_PLAY_LOOP:break; 269 default: 270 return DefWindowProc(hWnd,uMsg,wParam,lParam); 271  } 272 return 0; 273 } 274 275 //程序說明開始 276 //=========================================================// 277 // 功能:線程函數 278 //在這個函數中咱們接受一個建立線程時的一個參數this 由於線程能夠傳遞一個參數 279 // 在這個程序的處理過程當中 我很好的解決了在內中調用線程的例子 280 // 之前遇到這種問題幾回了,都是用一種不是很好的方式解決,今天算是搞清楚了 281 // 在類中建立線程,那麼線程函數必須爲全局函數,或者是靜態函數,由於線程函數只能有一個參數,若是爲成員函數,那麼就會有一個默認的this 282 // 因此不行 我首先將它定義爲友元函數,而後從線程函數中傳遞參數this這樣就能夠很好的解決這個問題了 283 // 參數:this指針 284 // 返回 :DWORD 285 // 主要思路: 286 // 調用類的方法建立一個隱藏的窗口 287 // 調用方法:系統自動調用 288 // 做者:張敏 289 // 日期:2012-1-11 郵箱 zhang19min88@163.com 290 // 說明: 291 //=========================================================// 292 DWORD WINAPI ThreadProc(LPVOID lParam) 293 { 294 ZMCMusic *pMusic=NULL; 295 pMusic=(ZMCMusic *)lParam; 296 return pMusic->MakeWindow(); 297 } 298 299 //程序說明開始 300 //=========================================================// 301 // 功能:啓動一個新的線程來建立一個窗口 302 // 參數:無 303 // 返回 :int 304 // 主要思路: 305 // 建立一個新的線程 306 // 調用方法:系統自動調用 307 // 做者:張敏 308 // 日期:2012-1-11 郵箱 zhang19min88@163.com 309 // 說明: 310 //=========================================================// 311 int ZMCMusic::CreateWindowInThread() 312 { 313 m_hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadProc,(LPVOID)this,0,&m_dwThreadID); 314 WaitForSingleObject(m_hThread,500); 315 return 0; 316 } 317 318 //程序說明開始 319 //=========================================================// 320 // 功能:輸出最近一次的錯誤信息 321 // 返回 :成功執行返回真 不然返回假 322 // 主要思路: 323 // 調用InternetReadFile函數 324 // 調用方法: 325 // 做者:張敏 326 // 日期:2012-1-7 郵箱 zhang19min88@163.com 327 // 說明: 328 //=========================================================// 329 void ZMCMusic::ShowError() 330 { 331 #define ERROR_BUF 256 332  TCHAR szBuf[ERROR_BUF]; 333  LPVOID lpMsgBuf; 334 DWORD dw=GetLastError(); 335 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,NULL,dw,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR)&lpMsgBuf,0,NULL); 336 wsprintf(szBuf,_T("執行失敗!錯誤碼爲:%d. 錯誤緣由爲:%s\n"),dw,lpMsgBuf); 337 MessageBox(NULL,szBuf,_T("錯誤"),MB_OK); 338 } 339 //程序說明開始 340 //=========================================================// 341 // 功能:獲得文件當前播放的位置 342 // 返回 :無 343 // 主要思路: 344 // 發送MCI_STATUS命令得到 345 // 主要是獲得狀態 346 // 調用方法: 347 // 做者:張敏 348 // 日期:2012-1-7 郵箱 zhang19min88@163.com 349 // 說明: 350 //=========================================================// 351 void ZMCMusic::GetCurPos() 352 { 353  MCI_STATUS_PARMS mciStatusParms; 354 mciStatusParms.dwItem=MCI_STATUS_POSITION; 355 if(mciSendCommand( m_uDeviceID , MCI_STATUS , MCI_STATUS_ITEM , (DWORD)(LPMCI_STATUS_PARMS) &mciStatusParms )==0 ) 356  { 357 m_nCurPos=mciStatusParms.dwReturn; 358  } 359 } 360 //程序說明開始 361 //=========================================================// 362 // 功能:獲得文件的長度 363 // 返回 :無 364 // 主要思路: 365 // 發送MCI_STATUS命令得到 366 // 主要是獲得狀態 367 // 調用方法: 368 // 做者:張敏 369 // 日期:2012-2-27 郵箱 zhang19min88@163.com 370 // 說明: 371 //=========================================================// 372 void ZMCMusic::GetFileLenth() 373 { 374  MCI_STATUS_PARMS mciStatusParms; 375 mciStatusParms.dwItem=MCI_STATUS_LENGTH;//得到文件的長度 376 if(mciSendCommand( m_uDeviceID , MCI_STATUS , MCI_STATUS_ITEM , (DWORD)(LPMCI_STATUS_PARMS) &mciStatusParms )==0 ) 377  { 378 m_nFileLen=mciStatusParms.dwReturn; 379  } 380 } 381 //程序說明開始 382 //=========================================================// 383 // 功能:將文件夾中的*.MP3文件和*.wav文件讀取出來按照順序添加到播放列表 384 // 返回 :無 385 // 主要思路: 386 // 在文件夾中查找*.mp3和*.wav的文件,而後放在容器中 387 // 調用方法: 388 // 做者:張敏 389 // 日期:2012-1-7 郵箱 zhang19min88@163.com 390 // 說明: 391 //=========================================================// 392 void ZMCMusic::AddPlayList(tstring tstrDir) 393 { 394 395 }
複製代碼

main.cppspa

複製代碼
 1 #include "cMusic.h"  2  3 void ShowMenu()  4 {  5 tcout<<"Press 0 to EXIT"<<endl;  6 tcout<<"Press 1 to PLAY"<<endl;  7 tcout<<"Press 2 to PAUSE"<<endl;  8 tcout<<"Press 3 to RESUSE"<<endl;  9 tcout<<"Press 4 to STOP"<<endl; 10 tcout<<"Press 5 to FULLSCAN"<<endl; 11 tcout<<"Press 6 to CLOSE"<<endl; 12 tcout<<"Press 7 to REPALY"<<endl; 13 tcout<<"Press 8 to SHOWPOS"<<endl; 14 tcout<<"Press 9 to STOP"<<endl; 15 16 } 17 int main() 18 { 19  tstring strFileName; 20 strFileName=_T("D:\\musicTest\\ifLove.mp3"); 21 // strFileName=_T("D:\\musicTest\\msg.mp3"); 22 23  ZMCMusic music; 24  music.Init(); 25 //music.AddPlayList(strFileName); 26  music.LoadMusicFile(strFileName); 27 28 int nKey=0; 29 bool bExit=false; 30 while(!bExit) 31  { 32  ShowMenu(); 33 tcout<<_T("You Command:"); 34 tcin>>nKey; 35 switch(nKey) 36  { 37 case 0:bExit=true;break; 38 case 1:music.Play();break; 39 case 2:music.Pause();break; 40 case 3:music.Resume();break; 41 //case 4:music.Stop();break; 42 case 6:music.Close();break; 43 case 7:music.Replay();break; 44 //case 8:SendMessage(g_hWnd,WM_CLOSE,NULL,NULL);break; 45 default:break; 46  } 47 Sleep(500); 48  } 49 return 0; 50 }
複製代碼

運行結果:

注意:

相關文章
相關標籤/搜索