自己封装的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 邮箱 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.cpp
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.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 }
运行结果:
aaarticlea/png;base64,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" alt="" />
注意:
这个类还有一些功能没有实现。
其中不是很理解PAUSE STOP CLOSE 这三个命令的区别。还待以后研究……
自己封装的CMusic类 【转】的更多相关文章
- .NET3.5中JSON用法以及封装JsonUtils工具类
.NET3.5中JSON用法以及封装JsonUtils工具类 我们讲到JSON的简单使用,现在我们来研究如何进行封装微软提供的JSON基类,达到更加方便.简单.强大且重用性高的效果. 首先创建一个类 ...
- MySQL数据库学习笔记(十一)----DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- MySQL数据库学习笔记(十)----JDBC事务处理、封装JDBC工具类
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- JAVA中封装JSONUtils工具类及使用
在JAVA中用json-lib-2.3-jdk15.jar包中提供了JSONObject和JSONArray基类,用于JSON的序列化和反序列化的操作.但是我们更习惯将其进一步封装,达到更好的重用. ...
- 使用libzplay库封装一个音频类
装载请说明原地址,谢谢~~ 前两天我已经封装好一个duilib中使用的webkit内核的浏览器控件和一个基于vlc的用于播放视频的视频控件,这两个控件可以分别用在放酷狗播放器的乐库功能和MV ...
- MySQL JDBC事务处理、封装JDBC工具类
MySQL数据库学习笔记(十)----JDBC事务处理.封装JDBC工具类 一.JDBC事务处理: 我们已经知道,事务的概念即:所有的操作要么同时成功,要么同时失败.在MySQL中提供了Commit. ...
- DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)
DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类) 一.DAO模式简介 DAO即Data Access Object,数据访问接口.数据访问:故名思义就是与数据库打交道.夹在业务逻辑与数据 ...
- [iOS]封装单例类
[iOS]封装单例类 今天在学习iOS的SQLite开发,发现在需要使用SQLite的每个视图中,都需要对数据库进行打开或关闭,觉得挺麻烦的:于是在想能否写个单例类对这些操作进行封(因以前一直在使用D ...
- 1.使用C++封装一个链表类LinkList
使用C++封装一个链表类LinkList.写出相应一个测试用例 链表需要提供 添加 修改删除 除重 合并 排序创建 销毁等接口. 不能调用库函数或者使用STL等类库 题目延伸********** ...
随机推荐
- GridView的RowCommand事件中获取每行控件的值
//获取当前行 GridViewRow gvr = (GridViewRow)((Control)e.CommandSource).Parent.Parent; //获取 ...
- 大数据学习——spark笔记
变量的定义 val a: Int = 1 var b = 2 方法和函数 区别:函数可以作为参数传递给方法 方法: def test(arg: Int): Int=>Int ={ 方法体 } v ...
- python-高级编程-01
[1] 列表推导 问题 我们需要一个[2,4,6,8] 这样的列表 传统写法 res = [] for i in range(10): if i %2 == 0:res.append(i) print ...
- python 获得列表中每个元素出现次数的最快方法
import collections import numpy as np import random import time def list_to_dict(lst): dic = {} for ...
- Django底层原理简介与安装
Django环境目录搭建一栏: 利用wsgiref模块封装好的socket搭建服务端: #利用wsgiref模块封装好的socket演示操作(例如accept\recv) #也可以实现socket服务 ...
- AtCoder Regular Contest 091
数学场,做到怀疑人生系列 C - Flip,Flip, and Flip...... Time limit : 2sec / Memory limit : 256MB Score : 300 poin ...
- PDO PDO_MYSQL MYSQLI MYSQL 的区别
MYSQL,MYSQLI 这两个扩展本身就是访问MYSQL数据库的驱动 PDO则是一个抽象层接口 向程序员提供可调用的API是由,MYSQL驱动.MYSQLI驱动,以及PDO来提供. PDO_MYSQ ...
- ACM程序设计选修课——1044: (ds:队列)打印队列(queue模拟)
问题 A: (ds:队列)打印队列 时间限制: 1 Sec 内存限制: 128 MB 提交: 25 解决: 4 [提交][状态][讨论版] 题目描述 网络工程实验室只有一台打印机,它承担了非常繁重 ...
- [luoguP3231] [HNOI2013]消毒(最小点覆盖 + 状压)
传送门 考虑贪心,控制某一维为1,另两位最大是最优的,也就是一次选一个厚度为1的面 那么对于每个点,可以有3种面是可以选到它的 然后gg 考虑二维的状态,一个平面,有些点,一次选一行或一列最优 那么每 ...
- Java防止SQL注入的途径介绍
为了防止SQL注入,最简洁的办法是杜绝SQL拼接,SQL注入攻击能得逞是因为在原有SQL语句中加入了新的逻辑,如果使用PreparedStatement来代替Statement来执行SQL语句,其后只 ...