自己封装的CMusic类 【转】

http://www.cnblogs.com/zhangminaxiang/archive/2013/02/27/2936011.html

缘由:

  在改正俄罗斯方块程序的功能的时候,想给这个程序增加一个背景音乐。本想用PlayWave来做的,但想到这个功能十分常用,那还不如封装一个自己的CMusic

类,以备不时之需。本来以为很容易的,可是在真正操作的时候,却出现了一个问题,就是无法准确的知道什么时候音乐播放完成。问题的难道就在于,怎样将类的成员函数作为窗口的回调函数。

 原本用thunk来解决这个问题的,但是在解决的时候出现了一个问题,调试了好几天都没有解决。直到最近才解决。(也就是前一篇文章的由来)

代码:(前面定义的宏主要是解决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  邮箱 [email protected]
 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.cpp

  1 #include "cMusic.h"
  2 //程序说明开始
  3 //=========================================================//
  4 // 功能:类的构造函数,由于本类需要 创建一个隐藏的窗口,用来接收
  5 //   播放完成之后的消息。所以在构造类的时候,很自然也需要构建一个
  6 //   隐藏的窗口
  7 // 参数:无
  8 // 返回 :无
  9 // 主要思路:
 10 //            初始化一些变量 并且调用createThread函数创建一个线程,并且在线程中
 11 // 创建一个窗口
 12 // 调用方法:系统自动调用
 13 // 作者:张敏
 14 // 日期:2012-1-11  邮箱 [email protected]
 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  邮箱 [email protected]
 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  邮箱 [email protected]
 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  邮箱 [email protected]
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  邮箱 [email protected]
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  邮箱 [email protected]
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  邮箱 [email protected]
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  邮箱 [email protected]
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  邮箱 [email protected]
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  邮箱 [email protected]
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  邮箱 [email protected]
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  邮箱 [email protected]
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  邮箱 [email protected]
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  邮箱 [email protected]
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  邮箱 [email protected]
390 // 说明:
391 //=========================================================//
392 void ZMCMusic::AddPlayList(tstring tstrDir)
393 {
394
395 }

main.cpp

 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 }

运行结果:

注意:

这个类还有一些功能没有实现。

其中不是很理解PAUSE  STOP CLOSE 这三个命令的区别。还待以后研究……

时间: 2024-10-23 18:23:58

自己封装的CMusic类 【转】的相关文章

DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)

一.DAO模式简介 DAO即Data Access Object,数据访问接口.数据访问:故名思义就是与数据库打交道.夹在业务逻辑与数据库资源中间. DAO模式实际上是两个模式的组合,即Data Accessor (数据访问者)模式和 Active Domain Object(领域对象)模式.Data Accessor 模式实现了数据访问和业务逻辑的分离:Active Domain Object 模式实现了业务数据的对象化封装. 需要注意的是,DAO设计模式是Java EE中的设计模式,而非Ja

MySQL数据库学习笔记(十)----JDBC事务处理、封装JDBC工具类

首先需要回顾一下上一篇文章中的内容:MySQL数据库学习笔记(九)----JDBC的PreparedStatement接口重构增删改查 一.JDBC事务处理: 我们已经知道,事务的概念即:所有的操作要么同时成功,要么同时失败.在MySQL中提供了Commit.Rollback命令进行事务的提交与回滚.实际上在JDBC中也存在事务处理,如果要想进行事务处理的话,则必须按照以下的步骤完成. JDBC中事务处理的步骤: 1.要取消掉JDBC的自动提交:void setAutoCommit(boolea

1.使用C++封装一个链表类LinkList

 使用C++封装一个链表类LinkList.写出相应一个测试用例 链表需要提供 添加 修改删除 除重 合并 排序创建 销毁等接口. 不能调用库函数或者使用STL等类库 题目延伸***********逆置链表********** LinkNode.h #ifndef LINKNODE_H #define LINKNODE_H #include <iostream> class LinkNode { public: int m_idata; LinkNode* m_pnext; }; #end

Java中如何使封装自己的类,建立并使用自己的类库?

转自:http://blog.csdn.net/luoweifu/article/details/7281494 随着自己的编程经历的积累会发现往往自己在一些项目中写的类在别的项目中也会有多次用到.你肯定会想:如何自己的写的一些常用的类积累起来,生成自己的类库?如果是这样的话,很庆幸,你遇到通道中人了,因为我也是这样做的.下面就介绍一下我是怎么做的吧 一.先来明白一下关于classpath和path的概念 path是java中用来进行编译和运行的程序所在的路径,而classpath是类所在的路径

MFC--串口编程---WIN API的方式将串扣操作封装在线程类中

串口采集数据 本文档介绍的是如何获取串口原始数据并将原始数据解析成可处理或可展示的数据. 一.串口采集有很多方式: 1).MFC有一个专门的控件,直接编程采集,一个控件只能采集一个串口,而且串口名字比如是COM20可能就打不开(这里我没有实践,师兄给这样说的),波特率太高读数会出错. 2).利用Windows API通信函数(该工程里面就采用的这种方式) 3).利用Visual C++的标准通信函数_inp._inpw._inpd._outp等直接对串口进行操作. 4).第三方编写的通信类. 二

封装JDBC工具类

JDBC连接数据库基本的步骤是固定的,这样就可以考虑封装一个工具类来简化数据库操作. 封装时用到了Java中的properties配置文件,是以一种键值对的形式存在的,可以把连接数据库要动态的信息保存到里面,这样比较直观,不容易出错,而且容易维护. 把配置文件放到src下就可以,如果要放到包下面就配置文件的相对路径就必须从包名开始. Demo : db.properties mysqlDriver=com.mysql.jdbc.Driver mysqlURL=jdbc:mysql://local

ios中封装网络请求类

ios中封装网络请求类 #import "JSNetWork.h" //asiHttpRequest #import "ASIFormDataRequest.h" //xml 的解析 #import "UseXmlParser.h" //判断是否联网 #import "Reachability.h" //sbJson,判断json的解析 #import "JSON.h" @implementation JS

导入导出封装的工具类 (一) 利用POI封装

对于导入导出各个项目中几乎都会用到,记得在高校平台中封装过导入导出这部分今天看了看是利用JXL封装的而经理说让我用POI写写导出,这两个导入导出框架是目前比较流程和常用的框架,有必要都了解一下. 写了写代码觉得导入导出这一块底层都是一样的,几乎所有的框架和别的牛人也好都是底层利用POI或JXL实现,比的是谁对这部分封装的好而且每个项目中对导入导出具体的细节是不同的,因此,有必要了解了解怎么样操作POI,学学使用它的API做导入导出也许第一步你封装的没有别人那么好,你也会收获很多了解他们封装的思路

JAVA中封装JSONUtils工具类及使用

在JAVA中用json-lib-2.3-jdk15.jar包中提供了JSONObject和JSONArray基类,用于JSON的序列化和反序列化的操作.但是我们更习惯将其进一步封装,达到更好的重用. 封装后的JSON工具类JSONUtils.java代码如下: JSONUtils代码,点击展开 import java.util.ArrayList;import java.util.Collection;import java.util.HashMap;import java.util.Itera