7845c427fc8b32ae54ee486da91a98d4ca2fb767
[reactos.git] / reactos / base / applications / mplay32 / mplay32.c
1 /*
2 * PROJECT: ReactOS Multimedia Player
3 * FILE: base/applications/mplay32/mplay32.c
4 * PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org)
5 */
6
7 #include "mplay32.h"
8
9 #define IDT_PLAYTIMER 1000
10
11 #define MAIN_WINDOW_HEIGHT 125
12 #define MAIN_WINDOW_MIN_WIDTH 250
13 #define MAX_MCISTR 256
14
15 HINSTANCE hInstance = NULL;
16 HWND hTrackBar = NULL;
17 HWND hToolBar = NULL;
18 HWND hTimeDisplay = NULL;
19 HMENU hMainMenu = NULL;
20
21 TCHAR szAppTitle[256] = _T("");
22 TCHAR szDefaultFilter[MAX_PATH] = _T("");
23 TCHAR szCurrentFile[MAX_PATH] = _T("");
24 LPTSTR szFilter = NULL;
25
26 WORD wDeviceId = 0;
27 BOOL bRepeat = FALSE;
28 BOOL bIsSingleWindow = FALSE;
29 UINT MaxFilePos = 0;
30 RECT PrevWindowPos;
31
32 static DWORD GetDeviceMode(HWND hwnd);
33
34 /* ToolBar Buttons */
35 static const TBBUTTON Buttons[] =
36 { /* iBitmap, idCommand, fsState, fsStyle, bReserved[2], dwData, iString */
37 {TBICON_PLAY, IDC_PLAY, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
38 {TBICON_STOP, IDC_STOP, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
39 {TBICON_EJECT, IDC_EJECT, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
40 {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0},
41 {TBICON_BACKWARD, IDC_BACKWARD, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
42 {TBICON_SEEKBACK, IDC_SEEKBACK, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
43 {TBICON_SEEKFORW, IDC_SEEKFORW, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
44 {TBICON_FORWARD, IDC_FORWARD, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
45 // {TBICON_PAUSE, IDC_PAUSE, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}
46 };
47
48 void EnableMenuItems(HWND hwnd)
49 {
50 MCIERROR mciError;
51 MCI_GENERIC_PARMS mciGeneric;
52 MCI_DGV_RECT_PARMS mciVideoRect;
53 MCI_DGV_WINDOW_PARMSW mciVideoWindow;
54
55 EnableMenuItem(hMainMenu, IDM_CLOSE_FILE, MF_BYCOMMAND | MF_ENABLED);
56
57 mciError = mciSendCommand(wDeviceId, MCI_CONFIGURE, MCI_TEST, (DWORD_PTR)&mciGeneric);
58 if (mciError == 0)
59 {
60 EnableMenuItem(hMainMenu, IDM_DEVPROPS, MF_BYCOMMAND | MF_ENABLED);
61 }
62
63 mciVideoWindow.hWnd = hwnd;
64
65 mciError = mciSendCommand(wDeviceId, MCI_WINDOW, MCI_DGV_WINDOW_HWND | MCI_TEST, (DWORD_PTR)&mciVideoWindow);
66 if (!mciError)
67 {
68 mciError = mciSendCommand(wDeviceId, MCI_WHERE, MCI_DGV_WHERE_SOURCE | MCI_TEST, (DWORD_PTR)&mciVideoRect);
69 if (!mciError)
70 {
71 EnableMenuItem(hMainMenu, IDM_SWITCHVIEW, MF_BYCOMMAND | MF_ENABLED);
72 }
73 }
74 }
75
76 void DisableMenuItems(void)
77 {
78 EnableMenuItem(hMainMenu, IDM_CLOSE_FILE, MF_BYCOMMAND | MF_GRAYED);
79 EnableMenuItem(hMainMenu, IDM_DEVPROPS, MF_BYCOMMAND | MF_GRAYED);
80 EnableMenuItem(hMainMenu, IDM_SWITCHVIEW, MF_BYCOMMAND | MF_GRAYED);
81 }
82
83 void ResizeClientArea(HWND hwnd, int nWidth, int nHeight)
84 {
85 RECT rcClientRect;
86 RECT rcWindowRect;
87 POINT ptDifference;
88
89 GetClientRect(hwnd, &rcClientRect);
90 GetWindowRect(hwnd, &rcWindowRect);
91 ptDifference.x = (rcWindowRect.right - rcWindowRect.left) - rcClientRect.right;
92 ptDifference.y = (rcWindowRect.bottom - rcWindowRect.top) - rcClientRect.bottom;
93 MoveWindow(hwnd, rcWindowRect.left, rcWindowRect.top, nWidth + ptDifference.x, nHeight + ptDifference.y, TRUE);
94 }
95
96 void UpdateWindowCaption(HWND hwnd)
97 {
98 TCHAR szNewTitle[MAX_PATH + 3 + 256];
99 TCHAR szStatus[128];
100
101 if (wDeviceId == 0)
102 {
103 SetWindowText(hwnd, szAppTitle);
104 return;
105 }
106
107 switch (GetDeviceMode(hwnd))
108 {
109 case MCI_MODE_PAUSE:
110 {
111 LoadString(hInstance, IDS_MODE_PAUSE, szStatus, ARRAYSIZE(szStatus));
112 break;
113 }
114
115 case MCI_MODE_STOP:
116 {
117 LoadString(hInstance, IDS_MODE_STOP, szStatus, ARRAYSIZE(szStatus));
118 break;
119 }
120
121 case MCI_MODE_PLAY:
122 {
123 LoadString(hInstance, IDS_MODE_PLAY, szStatus, ARRAYSIZE(szStatus));
124 break;
125 }
126
127 case MCI_MODE_OPEN:
128 {
129 LoadString(hInstance, IDS_MODE_OPEN, szStatus, ARRAYSIZE(szStatus));
130 break;
131 }
132
133 case MCI_MODE_RECORD:
134 {
135 LoadString(hInstance, IDS_MODE_RECORD, szStatus, ARRAYSIZE(szStatus));
136 break;
137 }
138
139 case MCI_MODE_SEEK:
140 {
141 LoadString(hInstance, IDS_MODE_SEEK, szStatus, ARRAYSIZE(szStatus));
142 break;
143 }
144
145 case MCI_MODE_NOT_READY:
146 {
147 LoadString(hInstance, IDS_MODE_NOT_READY, szStatus, ARRAYSIZE(szStatus));
148 break;
149 }
150
151 default:
152 {
153 LoadString(hInstance, IDS_MODE_UNKNOWN, szStatus, ARRAYSIZE(szStatus));
154 }
155 }
156
157 StringCbPrintf(szNewTitle, sizeof(szNewTitle), _T("%s - %s (%s)"), szAppTitle, szCurrentFile, szStatus);
158 SetWindowText(hwnd, szNewTitle);
159 }
160
161 void UpdateTimeDisplay(HWND hwnd)
162 {
163 MCI_STATUS_PARMS mciStatus;
164 TCHAR szTime[MAX_MCISTR];
165 DWORD dwTimeFormat;
166
167 if (!wDeviceId)
168 {
169 SetWindowText(hwnd, _T(""));
170 return;
171 }
172
173 mciStatus.dwItem = MCI_STATUS_TIME_FORMAT;
174 mciStatus.dwReturn = 0;
175 mciSendCommand(wDeviceId, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
176 dwTimeFormat = mciStatus.dwReturn;
177
178 mciStatus.dwItem = MCI_STATUS_POSITION;
179 mciStatus.dwReturn = 0;
180 mciSendCommand(wDeviceId, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
181
182 switch(dwTimeFormat)
183 {
184 case MCI_FORMAT_MILLISECONDS:
185 {
186 int s, m, h;
187
188 s = (mciStatus.dwReturn / 1000) % 60;
189 m = ((mciStatus.dwReturn / (1000*60)) % 60);
190 h = ((mciStatus.dwReturn / (1000*60*60)) % 24);
191 StringCbPrintf(szTime, sizeof(szTime), _T("%02lu:%02lu:%02lu"), h, m, s);
192 break;
193 }
194
195 /* The time format is unknown, so use the returned position as is */
196 default:
197 {
198 StringCbPrintf(szTime, sizeof(szTime), _T("%lu"), mciStatus.dwReturn);
199 break;
200 }
201 }
202
203 SetWindowText(hwnd, szTime);
204 }
205
206 static VOID
207 ShowLastWin32Error(HWND hwnd)
208 {
209 LPTSTR lpMessageBuffer;
210 DWORD dwError = GetLastError();
211
212 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
213 NULL,
214 dwError,
215 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
216 (LPTSTR)&lpMessageBuffer,
217 0, NULL) != 0)
218 {
219 MessageBox(hwnd, lpMessageBuffer, szAppTitle, MB_OK | MB_ICONERROR);
220 if (lpMessageBuffer) LocalFree(lpMessageBuffer);
221 }
222 }
223
224 static VOID
225 SetImageList(HWND hwnd)
226 {
227 HIMAGELIST hImageList;
228
229 hImageList = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR24, 1, 1);
230 if (!hImageList)
231 {
232 ShowLastWin32Error(hwnd);
233 return;
234 }
235
236 ImageList_AddMasked(hImageList,
237 LoadImage(hInstance, MAKEINTRESOURCE(IDB_PLAYICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR),
238 RGB(255, 255, 255));
239
240 ImageList_AddMasked(hImageList,
241 LoadImage(hInstance, MAKEINTRESOURCE(IDB_STOPICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR),
242 RGB(255, 255, 255));
243
244 ImageList_AddMasked(hImageList,
245 LoadImage(hInstance, MAKEINTRESOURCE(IDB_EJECTICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR),
246 RGB(255, 255, 255));
247
248 ImageList_AddMasked(hImageList,
249 LoadImage(hInstance, MAKEINTRESOURCE(IDB_BACKWARDICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR),
250 RGB(255, 255, 255));
251
252 ImageList_AddMasked(hImageList,
253 LoadImage(hInstance, MAKEINTRESOURCE(IDB_SEEKBACKICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR),
254 RGB(255, 255, 255));
255
256 ImageList_AddMasked(hImageList,
257 LoadImage(hInstance, MAKEINTRESOURCE(IDB_SEEKFORWICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR),
258 RGB(255, 255, 255));
259
260 ImageList_AddMasked(hImageList,
261 LoadImage(hInstance, MAKEINTRESOURCE(IDB_FORWARDICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR),
262 RGB(255, 255, 255));
263
264 ImageList_AddMasked(hImageList,
265 LoadImage(hInstance, MAKEINTRESOURCE(IDB_PAUSEICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR),
266 RGB(255, 255, 255));
267
268 ImageList_Destroy((HIMAGELIST)SendMessage(hToolBar,
269 TB_SETIMAGELIST,
270 0,
271 (LPARAM)hImageList));
272 }
273
274 static VOID
275 ShowMCIError(HWND hwnd, MCIERROR mciError)
276 {
277 TCHAR szErrorMessage[MAX_MCISTR];
278 TCHAR szTempMessage[MAX_MCISTR + 44];
279
280 if (mciGetErrorString(mciError, szErrorMessage, ARRAYSIZE(szErrorMessage)) == FALSE)
281 {
282 LoadString(hInstance, IDS_DEFAULTMCIERRMSG, szErrorMessage, ARRAYSIZE(szErrorMessage));
283 }
284
285 StringCbPrintf(szTempMessage, sizeof(szTempMessage), _T("MMSYS%lu: %s"), mciError, szErrorMessage);
286 MessageBox(hwnd, szTempMessage, szAppTitle, MB_OK | MB_ICONEXCLAMATION);
287 }
288
289 static VOID
290 InitControls(HWND hwnd)
291 {
292 INT NumButtons = ARRAYSIZE(Buttons);
293
294 InitCommonControls();
295
296 /* Create trackbar */
297 hTrackBar = CreateWindowEx(0,
298 TRACKBAR_CLASS,
299 NULL,
300 TBS_ENABLESELRANGE | WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPSIBLINGS,
301 0,
302 0,
303 340,
304 20,
305 hwnd,
306 NULL,
307 hInstance,
308 NULL);
309 if (!hTrackBar)
310 {
311 ShowLastWin32Error(hwnd);
312 return;
313 }
314
315 /* Create toolbar */
316 hToolBar = CreateWindowEx(0,
317 TOOLBARCLASSNAME,
318 NULL,
319 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPSIBLINGS |
320 TBSTYLE_FLAT | CCS_BOTTOM | TBSTYLE_TOOLTIPS,
321 0,
322 40,
323 340,
324 30,
325 hwnd,
326 NULL,
327 hInstance,
328 NULL);
329 if (!hToolBar)
330 {
331 ShowLastWin32Error(hwnd);
332 return;
333 }
334
335 hTimeDisplay = CreateWindowEx(0,
336 L"STATIC",
337 NULL,
338 WS_CHILD | WS_VISIBLE | SS_CENTER | SS_SUNKEN,
339 195,
340 4,
341 135,
342 18,
343 hToolBar,
344 NULL,
345 hInstance,
346 NULL);
347 if (!hTimeDisplay)
348 {
349 ShowLastWin32Error(hwnd);
350 return;
351 }
352
353 SetImageList(hwnd);
354 SendMessage(hToolBar, TB_ADDBUTTONS, NumButtons, (LPARAM)Buttons);
355 }
356
357 static VOID
358 SwitchViewMode(HWND hwnd)
359 {
360 MCIERROR mciError;
361 MCI_DGV_RECT_PARMS mciVideoRect;
362 MCI_DGV_WINDOW_PARMSW mciVideoWindow;
363 RECT rcToolbarRect;
364 RECT rcTempRect;
365
366 mciVideoWindow.hWnd = hwnd;
367
368 mciError = mciSendCommand(wDeviceId, MCI_WINDOW, MCI_DGV_WINDOW_HWND | MCI_TEST, (DWORD_PTR)&mciVideoWindow);
369 if (mciError != 0)
370 return;
371
372 mciError = mciSendCommand(wDeviceId, MCI_WHERE, MCI_DGV_WHERE_SOURCE | MCI_TEST, (DWORD_PTR)&mciVideoRect);
373 if (mciError != 0)
374 return;
375
376 if (!bIsSingleWindow)
377 {
378 GetWindowRect(hwnd, &PrevWindowPos);
379
380 SetParent(hTrackBar, hToolBar);
381
382 mciError = mciSendCommand(wDeviceId, MCI_WHERE, MCI_DGV_WHERE_SOURCE, (DWORD_PTR)&mciVideoRect);
383 if (mciError != 0)
384 {
385 ShowMCIError(hwnd, mciError);
386 return;
387 }
388
389 GetWindowRect(hToolBar, &rcToolbarRect);
390 ResizeClientArea(hwnd, mciVideoRect.rc.right, mciVideoRect.rc.bottom + (rcToolbarRect.bottom - rcToolbarRect.top));
391
392 mciError = mciSendCommand(wDeviceId, MCI_WINDOW, MCI_DGV_WINDOW_HWND, (DWORD_PTR)&mciVideoWindow);
393 if (mciError != 0)
394 {
395 ShowMCIError(hwnd, mciError);
396 return;
397 }
398
399 GetWindowRect(hToolBar, &rcTempRect);
400 MoveWindow(hTrackBar, 180, 0, rcTempRect.right - rcTempRect.left - 322, 25, TRUE);
401 MoveWindow(hTimeDisplay, rcTempRect.right - rcTempRect.left - 140, 4, 135, 18, TRUE);
402
403 CheckMenuItem(hMainMenu, IDM_SWITCHVIEW, MF_BYCOMMAND | MF_CHECKED);
404 bIsSingleWindow = TRUE;
405 }
406 else
407 {
408 bIsSingleWindow = FALSE;
409 CheckMenuItem(hMainMenu, IDM_SWITCHVIEW, MF_BYCOMMAND | MF_UNCHECKED);
410
411 mciVideoWindow.hWnd = MCI_DGV_WINDOW_DEFAULT;
412 mciError = mciSendCommand(wDeviceId, MCI_WINDOW, MCI_DGV_WINDOW_HWND, (DWORD_PTR)&mciVideoWindow);
413 if (mciError != 0)
414 {
415 ShowMCIError(hwnd, mciError);
416 return;
417 }
418
419 SetParent(hTrackBar, hwnd);
420
421 MoveWindow(hwnd, PrevWindowPos.left, PrevWindowPos.top, PrevWindowPos.right - PrevWindowPos.left, PrevWindowPos.bottom - PrevWindowPos.top, TRUE);
422 }
423 }
424
425 static DWORD
426 GetNumDevices(VOID)
427 {
428 MCI_SYSINFO_PARMS mciSysInfo;
429 DWORD dwNumDevices = 0;
430
431 mciSysInfo.dwCallback = 0;
432 mciSysInfo.lpstrReturn = (LPTSTR)&dwNumDevices;
433 mciSysInfo.dwRetSize = sizeof(dwNumDevices);
434 mciSysInfo.dwNumber = 0;
435 mciSysInfo.wDeviceType = MCI_ALL_DEVICE_ID;
436
437 mciSendCommand(MCI_ALL_DEVICE_ID, MCI_SYSINFO, MCI_SYSINFO_QUANTITY, (DWORD_PTR)&mciSysInfo);
438
439 return *(DWORD*)mciSysInfo.lpstrReturn;
440 }
441
442 static DWORD
443 GetDeviceName(DWORD dwDeviceIndex, LPTSTR lpDeviceName, DWORD dwDeviceNameSize)
444 {
445 MCI_SYSINFO_PARMS mciSysInfo;
446
447 mciSysInfo.dwCallback = 0;
448 mciSysInfo.lpstrReturn = lpDeviceName;
449 mciSysInfo.dwRetSize = dwDeviceNameSize;
450 mciSysInfo.dwNumber = dwDeviceIndex;
451 mciSysInfo.wDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
452
453 return mciSendCommand(MCI_ALL_DEVICE_ID, MCI_SYSINFO, MCI_SYSINFO_NAME, (DWORD_PTR)&mciSysInfo);
454 }
455
456 static DWORD
457 GetDeviceFriendlyName(LPTSTR lpDeviceName, LPTSTR lpFriendlyName, DWORD dwFriendlyNameSize)
458 {
459 MCIERROR mciError;
460 MCI_OPEN_PARMS mciOpen;
461 MCI_INFO_PARMS mciInfo;
462 MCI_GENERIC_PARMS mciGeneric;
463
464 mciOpen.dwCallback = 0;
465 mciOpen.wDeviceID = 0;
466 mciOpen.lpstrDeviceType = lpDeviceName;
467 mciOpen.lpstrElementName = NULL;
468 mciOpen.lpstrAlias = NULL;
469
470 mciError = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_WAIT, (DWORD_PTR)&mciOpen);
471 if (mciError != 0)
472 return mciError;
473
474 mciInfo.dwCallback = 0;
475 mciInfo.lpstrReturn = lpFriendlyName;
476 mciInfo.dwRetSize = dwFriendlyNameSize;
477
478 mciError = mciSendCommand(mciOpen.wDeviceID, MCI_INFO, MCI_INFO_PRODUCT, (DWORD_PTR)&mciInfo);
479
480 mciGeneric.dwCallback = 0;
481 mciSendCommand(mciOpen.wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)&mciGeneric);
482
483 return mciError;
484 }
485
486 static BOOL
487 DeviceUsesFiles(LPTSTR lpDeviceName)
488 {
489 MCIERROR mciError;
490 MCI_OPEN_PARMS mciOpen;
491 MCI_GETDEVCAPS_PARMS mciDevCaps;
492 MCI_GENERIC_PARMS mciGeneric;
493
494 mciOpen.dwCallback = 0;
495 mciOpen.wDeviceID = 0;
496 mciOpen.lpstrDeviceType = lpDeviceName;
497 mciOpen.lpstrElementName = NULL;
498 mciOpen.lpstrAlias = NULL;
499
500 mciError = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_WAIT, (DWORD_PTR)&mciOpen);
501 if (mciError != 0)
502 return FALSE;
503
504 mciDevCaps.dwCallback = 0;
505 mciDevCaps.dwReturn = 0;
506 mciDevCaps.dwItem = MCI_GETDEVCAPS_USES_FILES;
507
508 mciError = mciSendCommand(mciOpen.wDeviceID, MCI_GETDEVCAPS, MCI_WAIT | MCI_GETDEVCAPS_ITEM, (DWORD_PTR)&mciDevCaps);
509 if (mciError != 0)
510 return FALSE;
511
512 mciGeneric.dwCallback = 0;
513 mciSendCommand(mciOpen.wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)&mciGeneric);
514
515 return (BOOL)mciDevCaps.dwReturn;
516 }
517
518 static MCIERROR
519 CloseMciDevice(VOID)
520 {
521 MCIERROR mciError;
522 MCI_GENERIC_PARMS mciGeneric;
523
524 if (wDeviceId)
525 {
526 mciError = mciSendCommand(wDeviceId, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)&mciGeneric);
527 if (mciError != 0) return mciError;
528 wDeviceId = 0;
529 }
530
531 UpdateTimeDisplay(hTimeDisplay);
532
533 DisableMenuItems();
534
535 return 0;
536 }
537
538 static MCIERROR
539 OpenMciDevice(HWND hwnd, LPTSTR lpType, LPTSTR lpFileName)
540 {
541 MCIERROR mciError;
542 MCI_STATUS_PARMS mciStatus;
543 MCI_OPEN_PARMS mciOpen;
544 DWORD dwFlags = MCI_WAIT;
545 LPTSTR lpStr;
546
547 if (wDeviceId)
548 CloseMciDevice();
549
550 mciOpen.lpstrDeviceType = lpType;
551 mciOpen.lpstrElementName = lpFileName;
552 mciOpen.dwCallback = 0;
553 mciOpen.wDeviceID = 0;
554 mciOpen.lpstrAlias = NULL;
555
556 if (lpType)
557 dwFlags |= MCI_OPEN_TYPE;
558
559 if (lpFileName)
560 dwFlags |= MCI_OPEN_ELEMENT;
561
562 mciError = mciSendCommand(0, MCI_OPEN, dwFlags, (DWORD_PTR)&mciOpen);
563 if (mciError != 0)
564 return mciError;
565
566 mciStatus.dwItem = MCI_STATUS_LENGTH;
567
568 mciError = mciSendCommand(mciOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&mciStatus);
569 if (mciError != 0)
570 return mciError;
571
572 SendMessage(hTrackBar, TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)1);
573 SendMessage(hTrackBar, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)mciStatus.dwReturn);
574 SendMessage(hTrackBar, TBM_SETPAGESIZE, 0, 10);
575 SendMessage(hTrackBar, TBM_SETLINESIZE, 0, 1);
576 SendMessage(hTrackBar, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)1);
577
578 if (mciStatus.dwReturn < 10000)
579 {
580 SendMessage(hTrackBar, TBM_SETTICFREQ, (WPARAM)100, (LPARAM)0);
581 }
582 else if (mciStatus.dwReturn < 100000)
583 {
584 SendMessage(hTrackBar, TBM_SETTICFREQ, (WPARAM)1000, (LPARAM)0);
585 }
586 else if (mciStatus.dwReturn < 1000000)
587 {
588 SendMessage(hTrackBar, TBM_SETTICFREQ, (WPARAM)10000, (LPARAM)0);
589 }
590 else
591 {
592 SendMessage(hTrackBar, TBM_SETTICFREQ, (WPARAM)100000, (LPARAM)0);
593 }
594
595 MaxFilePos = mciStatus.dwReturn;
596 wDeviceId = mciOpen.wDeviceID;
597
598 /* NOTE: Everything above this line may be done instead in OpenMediaFile() */
599
600 if (lpFileName)
601 {
602 lpStr = _tcsrchr(lpFileName, _T('\\'));
603 if (lpStr) // Get only the file name (skip the last path separator)
604 lpStr++;
605 else
606 lpStr = lpFileName;
607 }
608 else
609 lpStr = lpType;
610
611 StringCbCopy(szCurrentFile, sizeof(szCurrentFile), lpStr);
612
613 EnableMenuItems(hwnd);
614
615 UpdateTimeDisplay(hTimeDisplay);
616 UpdateWindowCaption(hwnd);
617
618 return 0;
619 }
620
621 static DWORD
622 GetDeviceMode(HWND hwnd)
623 {
624 MCIERROR mciError;
625 MCI_STATUS_PARMS mciStatus;
626
627 mciStatus.dwItem = MCI_STATUS_MODE;
628 mciError = mciSendCommand(wDeviceId, MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
629 if (mciError != 0)
630 {
631 ShowMCIError(hwnd, mciError);
632 return MCI_MODE_NOT_READY;
633 }
634
635 return mciStatus.dwReturn;
636 }
637
638 static VOID
639 StopPlayback(HWND hwnd)
640 {
641 MCIERROR mciError;
642 MCI_GENERIC_PARMS mciGeneric;
643 MCI_SEEK_PARMS mciSeek;
644
645 if (wDeviceId == 0) return;
646
647 KillTimer(hwnd, IDT_PLAYTIMER);
648 SendMessage(hTrackBar, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)1);
649
650 mciGeneric.dwCallback = (DWORD_PTR)hwnd;
651 mciError = mciSendCommand(wDeviceId, MCI_STOP, MCI_WAIT, (DWORD_PTR)&mciGeneric);
652 if (mciError != 0)
653 {
654 ShowMCIError(hwnd, mciError);
655 return;
656 }
657
658 mciSendCommand(wDeviceId, MCI_SEEK, MCI_WAIT | MCI_SEEK_TO_START, (DWORD_PTR)&mciSeek);
659
660 UpdateTimeDisplay(hTimeDisplay);
661 UpdateWindowCaption(hwnd);
662
663 SendMessage(hToolBar,
664 TB_SETCMDID,
665 0,
666 IDC_PLAY);
667 SendMessage(hToolBar,
668 TB_CHANGEBITMAP,
669 IDC_PLAY,
670 IDB_PLAYICON - IDB_PLAYICON);
671 }
672
673 static VOID
674 SeekPlayback(HWND hwnd, DWORD dwNewPos)
675 {
676 MCIERROR mciError;
677 MCI_SEEK_PARMS mciSeek;
678 MCI_PLAY_PARMS mciPlay;
679
680 if (wDeviceId == 0) return;
681
682 mciSeek.dwTo = (DWORD_PTR)dwNewPos;
683 mciError = mciSendCommand(wDeviceId, MCI_SEEK, MCI_WAIT | MCI_TO, (DWORD_PTR)&mciSeek);
684 if (mciError != 0)
685 {
686 ShowMCIError(hwnd, mciError);
687 }
688
689 mciPlay.dwCallback = (DWORD_PTR)hwnd;
690 mciError = mciSendCommand(wDeviceId, MCI_PLAY, MCI_NOTIFY, (DWORD_PTR)&mciPlay);
691 if (mciError != 0)
692 {
693 ShowMCIError(hwnd, mciError);
694 }
695 }
696
697 static VOID
698 SeekBackPlayback(HWND hwnd)
699 {
700 MCI_STATUS_PARMS mciStatus;
701 DWORD dwNewPos;
702
703 if (wDeviceId == 0) return;
704
705 mciStatus.dwItem = MCI_STATUS_POSITION;
706 mciSendCommand(wDeviceId, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
707
708 dwNewPos = mciStatus.dwReturn - 1;
709
710 if ((UINT)dwNewPos <= 1)
711 {
712 StopPlayback(hwnd);
713 }
714 else
715 {
716 SeekPlayback(hwnd, dwNewPos);
717 }
718 }
719
720 static VOID
721 SeekForwPlayback(HWND hwnd)
722 {
723 MCI_STATUS_PARMS mciStatus;
724 DWORD dwNewPos;
725
726 if (wDeviceId == 0) return;
727
728 mciStatus.dwItem = MCI_STATUS_POSITION;
729 mciSendCommand(wDeviceId, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
730
731 dwNewPos = mciStatus.dwReturn + 1;
732
733 if ((UINT)dwNewPos >= MaxFilePos)
734 {
735 StopPlayback(hwnd);
736 }
737 else
738 {
739 SeekPlayback(hwnd, dwNewPos);
740 }
741 }
742
743 VOID CALLBACK
744 PlayTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
745 {
746 MCI_STATUS_PARMS mciStatus;
747 DWORD dwPos;
748
749 if (wDeviceId == 0) KillTimer(hwnd, IDT_PLAYTIMER);
750
751 mciStatus.dwItem = MCI_STATUS_POSITION;
752 mciSendCommand(wDeviceId, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
753 dwPos = mciStatus.dwReturn;
754
755 SendMessage(hTrackBar, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)dwPos);
756 UpdateTimeDisplay(hTimeDisplay);
757 }
758
759 static VOID
760 StartPlayback(HWND hwnd)
761 {
762 MCIERROR mciError;
763 MCI_PLAY_PARMS mciPlay;
764 MCI_SEEK_PARMS mciSeek;
765
766 SetTimer(hwnd, IDT_PLAYTIMER, 100, (TIMERPROC)PlayTimerProc);
767
768 mciSendCommand(wDeviceId, MCI_SEEK, MCI_WAIT | MCI_SEEK_TO_START, (DWORD_PTR)&mciSeek);
769
770 mciPlay.dwCallback = (DWORD_PTR)hwnd;
771 mciPlay.dwFrom = 0;
772 mciPlay.dwTo = MaxFilePos;
773
774 mciError = mciSendCommand(wDeviceId, MCI_PLAY, MCI_NOTIFY | MCI_FROM /*| MCI_TO*/, (DWORD_PTR)&mciPlay);
775 if (mciError != 0)
776 {
777 ShowMCIError(hwnd, mciError);
778 return;
779 }
780
781 UpdateWindowCaption(hwnd);
782
783 SendMessage(hToolBar,
784 TB_SETCMDID,
785 0,
786 IDC_PAUSE);
787 SendMessage(hToolBar,
788 TB_CHANGEBITMAP,
789 IDC_PAUSE,
790 IDB_PAUSEICON - IDB_PLAYICON);
791 }
792
793 static VOID
794 TogglePlaybackState(HWND hwnd)
795 {
796 MCIERROR mciError;
797 MCI_GENERIC_PARMS mciGeneric;
798 ULONG idBmp = IDB_PLAYICON;
799 ULONG idCmd = IDC_PLAY;
800
801 if (wDeviceId == 0) return;
802
803 switch (GetDeviceMode(hwnd))
804 {
805 case MCI_MODE_OPEN:
806 case MCI_MODE_STOP:
807 {
808 StartPlayback(hwnd);
809 return;
810 }
811
812 case MCI_MODE_PLAY:
813 {
814 mciGeneric.dwCallback = (DWORD_PTR)hwnd;
815 mciError = mciSendCommand(wDeviceId, MCI_PAUSE, MCI_WAIT, (DWORD_PTR)&mciGeneric);
816 idBmp = IDB_PLAYICON;
817 idCmd = IDC_PLAY;
818 break;
819 }
820
821 case MCI_MODE_PAUSE:
822 {
823 mciGeneric.dwCallback = (DWORD_PTR)hwnd;
824 mciError = mciSendCommand(wDeviceId, MCI_RESUME, MCI_WAIT, (DWORD_PTR)&mciGeneric);
825 idBmp = IDB_PAUSEICON;
826 idCmd = IDC_PAUSE;
827 break;
828 }
829
830 default:
831 {
832 return;
833 }
834 }
835
836 if (mciError != 0)
837 {
838 ShowMCIError(hwnd, mciError);
839 return;
840 }
841
842 UpdateWindowCaption(hwnd);
843
844 SendMessage(hToolBar,
845 TB_SETCMDID,
846 0,
847 idCmd);
848 SendMessage(hToolBar,
849 TB_CHANGEBITMAP,
850 idCmd,
851 idBmp - IDB_PLAYICON);
852 }
853
854 static VOID
855 ShowDeviceProperties(HWND hwnd)
856 {
857 MCIERROR mciError;
858 MCI_GENERIC_PARMS mciGeneric;
859
860 mciError = mciSendCommand(wDeviceId, MCI_CONFIGURE, MCI_WAIT, (DWORD_PTR)&mciGeneric);
861 if (mciError != 0)
862 {
863 ShowMCIError(hwnd, mciError);
864 }
865 }
866
867 static VOID
868 CloseMediaFile(HWND hwnd)
869 {
870 StopPlayback(hwnd);
871
872 if (bIsSingleWindow)
873 SwitchViewMode(hwnd);
874
875 CloseMciDevice();
876 UpdateWindowCaption(hwnd);
877 }
878
879 static VOID
880 OpenMediaFile(HWND hwnd, LPTSTR lpFileName, LPTSTR lpType)
881 {
882 MCIERROR mciError;
883
884 if (GetFileAttributes(lpFileName) == INVALID_FILE_ATTRIBUTES)
885 return;
886
887 if (wDeviceId)
888 CloseMediaFile(hwnd);
889
890 mciError = OpenMciDevice(hwnd, lpType, lpFileName);
891 if (mciError != 0)
892 {
893 ShowMCIError(hwnd, mciError);
894 return;
895 }
896
897 StartPlayback(hwnd);
898 }
899
900 static DWORD
901 InsertDeviceMenuItem(HMENU hMenu, UINT uItem, BOOL fByPosition, UINT uItemID, DWORD dwDeviceIndex)
902 {
903 MENUITEMINFO lpmii;
904 MCIERROR mciError;
905 TCHAR szDeviceName[MAX_MCISTR];
906 TCHAR szFriendlyName[MAX_MCISTR];
907
908 mciError = GetDeviceName(dwDeviceIndex, szDeviceName, sizeof(szDeviceName));
909 if (mciError)
910 {
911 return mciError;
912 }
913
914 mciError = GetDeviceFriendlyName(szDeviceName, szFriendlyName, sizeof(szFriendlyName));
915 if (mciError)
916 {
917 return mciError;
918 }
919
920 if (DeviceUsesFiles(szDeviceName))
921 {
922 StringCbCat(szFriendlyName, sizeof(szFriendlyName), _T("..."));
923 }
924
925 ZeroMemory(&lpmii, sizeof(MENUITEMINFO));
926 lpmii.cbSize = sizeof(lpmii);
927 lpmii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID;
928 lpmii.wID = uItemID;
929 lpmii.fType = MF_STRING;
930 lpmii.dwTypeData = szFriendlyName;
931 lpmii.dwItemData = dwDeviceIndex;
932 InsertMenuItem(hMenu, uItem, fByPosition, &lpmii);
933
934 return 0;
935 }
936
937 static VOID
938 BuildFileFilterAndDeviceMenu(VOID)
939 {
940 TCHAR szDeviceName[MAX_MCISTR];
941 TCHAR szFriendlyName[MAX_MCISTR];
942 TCHAR *szDevice = NULL;
943 static TCHAR szDefaultExtension[] = _T("*.*");
944 TCHAR *szExtensionList = NULL;
945 TCHAR *szExtension = NULL;
946 TCHAR *c = NULL;
947 TCHAR *d = NULL;
948 DWORD dwNumValues;
949 DWORD dwNumDevices;
950 DWORD dwValueNameLen;
951 DWORD dwValueDataSize;
952 DWORD dwMaskLen;
953 DWORD dwFilterSize;
954 DWORD dwDeviceSize;
955 DWORD dwExtensionLen;
956 DWORD dwPosition = 0;
957 DWORD i;
958 DWORD j;
959 UINT uSizeRemain;
960 UINT uMaskRemain;
961 HKEY hKey = NULL;
962
963 /* Always load the default (all files) filter */
964 LoadString(hInstance, IDS_ALL_TYPES_FILTER, szDefaultFilter, ARRAYSIZE(szDefaultFilter));
965
966 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\MCI Extensions"), 0, KEY_READ, &hKey) != ERROR_SUCCESS)
967 {
968 goto Failure;
969 }
970
971 if (RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwNumValues, &dwValueNameLen, &dwValueDataSize, NULL, NULL) != ERROR_SUCCESS)
972 {
973 goto Failure;
974 }
975
976 dwMaskLen = ((dwValueNameLen + 3) * dwNumValues) + 1;
977
978 szExtensionList = malloc(dwMaskLen * sizeof(TCHAR));
979 if (!szExtensionList)
980 goto Failure;
981
982 dwNumDevices = GetNumDevices();
983
984 /* Allocate space for every pair of Device and Extension Filter */
985 dwFilterSize = (MAX_MCISTR + (dwMaskLen * 2) + 5) * dwNumDevices;
986
987 /* Add space for the "All supported" entry */
988 dwFilterSize = (dwFilterSize + (dwMaskLen * 2) + 7) * sizeof(TCHAR) + sizeof(szDefaultFilter);
989
990 szFilter = malloc(dwFilterSize);
991 if (!szFilter)
992 goto Failure;
993
994 szExtension = malloc((dwValueNameLen + 1) * sizeof(TCHAR));
995 if (!szExtension)
996 goto Failure;
997
998 szDevice = malloc(dwValueDataSize + sizeof(TCHAR));
999 if (!szDevice)
1000 goto Failure;
1001
1002 ZeroMemory(szFilter, dwFilterSize);
1003
1004 uSizeRemain = dwFilterSize;
1005 c = szFilter;
1006
1007 for (j = 1; j <= dwNumDevices; j++)
1008 {
1009 if (GetDeviceName(j, szDeviceName, sizeof(szDeviceName)))
1010 {
1011 continue;
1012 }
1013
1014 if (GetDeviceFriendlyName(szDeviceName, szFriendlyName, sizeof(szFriendlyName)))
1015 {
1016 continue;
1017 }
1018
1019 /* Insert a menu item under the "Device" menu for every found MCI device */
1020 InsertDeviceMenuItem(GetSubMenu(hMainMenu, 3), dwPosition, TRUE, IDM_DEVICE_FIRST + dwPosition, j);
1021 dwPosition++;
1022
1023 /* Copy the default extension list, that may be overwritten after... */
1024 StringCbCopy(szExtensionList, dwMaskLen * sizeof(TCHAR), szDefaultExtension);
1025
1026 /* Try to determine the real extension list */
1027 uMaskRemain = dwMaskLen * sizeof(TCHAR);
1028 d = szExtensionList;
1029
1030 for (i = 0; i < dwNumValues; i++)
1031 {
1032 dwExtensionLen = dwValueNameLen + 1;
1033 dwDeviceSize = dwValueDataSize + sizeof(TCHAR);
1034
1035 ZeroMemory(szDevice, dwDeviceSize);
1036
1037 if (RegEnumValue(hKey, i, szExtension, &dwExtensionLen, NULL, NULL, (LPBYTE)szDevice, &dwDeviceSize) == ERROR_SUCCESS)
1038 {
1039 CharLowerBuff(szDevice, dwDeviceSize / sizeof(TCHAR));
1040 CharLowerBuff(szDeviceName, ARRAYSIZE(szDeviceName));
1041 if (_tcscmp(szDeviceName, szDevice) == 0)
1042 {
1043 CharLowerBuff(szExtension, dwExtensionLen);
1044 StringCbPrintfEx(d, uMaskRemain, &d, &uMaskRemain, 0, _T("%s%s%s"), _T("*."), szExtension, _T(";"));
1045 }
1046 }
1047 }
1048
1049 /* Remove the last separator */
1050 d--;
1051 uSizeRemain += sizeof(*d);
1052 *d = _T('\0');
1053
1054 /* Add the description */
1055 StringCbPrintfEx(c, uSizeRemain, &c, &uSizeRemain, 0, _T("%s (%s)"), szFriendlyName, szExtensionList);
1056
1057 /* Skip one char to seperate the description from the filter mask */
1058 c++;
1059 uSizeRemain -= sizeof(*c);
1060
1061 /* Append the filter mask */
1062 StringCbCopyEx(c, uSizeRemain, szExtensionList, &c, &uSizeRemain, 0);
1063
1064 /* Skip another char to seperate the elements of the filter mask */
1065 c++;
1066 uSizeRemain -= sizeof(*c);
1067 }
1068
1069 /* Build the full list of supported extensions */
1070 uMaskRemain = dwMaskLen * sizeof(TCHAR);
1071 d = szExtensionList;
1072
1073 for (i = 0; i < dwNumValues; i++)
1074 {
1075 dwExtensionLen = dwValueNameLen + 1;
1076
1077 if (RegEnumValue(hKey, i, szExtension, &dwExtensionLen, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1078 {
1079 CharLowerBuff(szExtension, dwExtensionLen);
1080 StringCbPrintfEx(d, uMaskRemain, &d, &uMaskRemain, 0, _T("%s%s%s"), _T("*."), szExtension, _T(";"));
1081 }
1082 }
1083
1084 /* Remove the last separator */
1085 d--;
1086 uSizeRemain += sizeof(*d);
1087 *d = _T('\0');
1088
1089 /* Add the default (all files) description */
1090 StringCbPrintfEx(c, uSizeRemain, &c, &uSizeRemain, 0, _T("%s (%s)"), szDefaultFilter, szExtensionList);
1091
1092 /* Skip one char to seperate the description from the filter mask */
1093 c++;
1094 uSizeRemain -= sizeof(*c);
1095
1096 /* Append the filter mask */
1097 StringCbCopyEx(c, uSizeRemain, szExtensionList, &c, &uSizeRemain, 0);
1098
1099 Cleanup:
1100 if (szExtensionList) free(szExtensionList);
1101 if (szExtension) free(szExtension);
1102 if (szDevice) free(szDevice);
1103 RegCloseKey(hKey);
1104
1105 return;
1106
1107 Failure:
1108 /* We failed at retrieving the supported files, so use the default filter */
1109 if (szFilter) free(szFilter);
1110 szFilter = szDefaultFilter;
1111
1112 uSizeRemain = sizeof(szDefaultFilter);
1113 c = szFilter;
1114
1115 /* Add the default (all files) description */
1116 StringCbPrintfEx(c, uSizeRemain, &c, &uSizeRemain, 0, _T("%s (%s)"), szDefaultFilter, szDefaultExtension);
1117
1118 /* Skip one char to seperate the description from the filter mask */
1119 c++;
1120 uSizeRemain -= sizeof(*c);
1121
1122 /* Append the filter mask */
1123 StringCbCopyEx(c, uSizeRemain, szDefaultExtension, &c, &uSizeRemain, 0);
1124
1125 goto Cleanup;
1126 }
1127
1128 static VOID
1129 CleanupFileFilter(VOID)
1130 {
1131 if (szFilter && szFilter != szDefaultFilter) free(szFilter);
1132 }
1133
1134 static VOID
1135 OpenFileDialog(HWND hwnd, DWORD dwFilterIndex, LPTSTR lpType)
1136 {
1137 OPENFILENAME OpenFileName;
1138 TCHAR szFile[MAX_PATH + 1] = _T("");
1139 TCHAR szCurrentDir[MAX_PATH];
1140
1141 ZeroMemory(&OpenFileName, sizeof(OpenFileName));
1142
1143 if (!GetCurrentDirectory(ARRAYSIZE(szCurrentDir), szCurrentDir))
1144 {
1145 StringCbCopy(szCurrentDir, sizeof(szCurrentDir), _T("c:\\"));
1146 }
1147
1148 OpenFileName.lStructSize = sizeof(OpenFileName);
1149 OpenFileName.hwndOwner = hwnd;
1150 OpenFileName.hInstance = hInstance;
1151 OpenFileName.lpstrFilter = szFilter;
1152 OpenFileName.lpstrFile = szFile;
1153 OpenFileName.nMaxFile = ARRAYSIZE(szFile);
1154 OpenFileName.lpstrInitialDir = szCurrentDir;
1155 OpenFileName.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_SHAREAWARE;
1156 OpenFileName.lpstrDefExt = _T("\0");
1157 OpenFileName.nFilterIndex = dwFilterIndex;
1158
1159 if (!GetOpenFileName(&OpenFileName))
1160 return;
1161
1162 OpenMediaFile(hwnd, OpenFileName.lpstrFile, lpType);
1163 }
1164
1165 static VOID
1166 HandleDeviceMenuItem(HWND hwnd, UINT uItem)
1167 {
1168 MENUITEMINFO lpmii;
1169 TCHAR szDeviceName[MAX_MCISTR];
1170 MCIERROR mciError;
1171
1172 ZeroMemory(&lpmii, sizeof(MENUITEMINFO));
1173 lpmii.cbSize = sizeof(lpmii);
1174 lpmii.fMask = MIIM_DATA;
1175 GetMenuItemInfo(hMainMenu, uItem, FALSE, &lpmii);
1176
1177 mciError = GetDeviceName(lpmii.dwItemData, szDeviceName, sizeof(szDeviceName));
1178 if (mciError)
1179 {
1180 ShowMCIError(hwnd, mciError);
1181 return;
1182 }
1183
1184 if (DeviceUsesFiles(szDeviceName))
1185 {
1186 OpenFileDialog(hwnd, uItem - IDM_DEVICE_FIRST + 1, szDeviceName);
1187 return;
1188 }
1189
1190 mciError = OpenMciDevice(hwnd, szDeviceName, NULL);
1191 if (mciError)
1192 {
1193 ShowMCIError(hwnd, mciError);
1194 }
1195
1196 return;
1197 }
1198
1199 LRESULT CALLBACK
1200 MainWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
1201 {
1202 switch (Message)
1203 {
1204 case WM_CREATE:
1205 {
1206 InitControls(hwnd);
1207 hMainMenu = GetMenu(hwnd);
1208 break;
1209 }
1210
1211 case WM_DROPFILES:
1212 {
1213 HDROP drophandle;
1214 TCHAR droppedfile[MAX_PATH];
1215
1216 drophandle = (HDROP)wParam;
1217 DragQueryFile(drophandle, 0, droppedfile, ARRAYSIZE(droppedfile));
1218 DragFinish(drophandle);
1219 OpenMediaFile(hwnd, droppedfile, NULL);
1220 break;
1221 }
1222
1223 case MM_MCINOTIFY:
1224 {
1225 if (wParam == MCI_NOTIFY_SUCCESSFUL)
1226 {
1227 StopPlayback(hwnd);
1228 if (bRepeat)
1229 {
1230 StartPlayback(hwnd);
1231 }
1232 }
1233 break;
1234 }
1235
1236 case WM_NOTIFY:
1237 {
1238 LPNMHDR pnmhdr = (LPNMHDR)lParam;
1239
1240 switch (pnmhdr->code)
1241 {
1242 case TTN_GETDISPINFO:
1243 {
1244 LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)lParam;
1245 UINT idButton = (UINT)lpttt->hdr.idFrom;
1246
1247 switch (idButton)
1248 {
1249 case IDC_PLAY:
1250 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PLAY);
1251 break;
1252 case IDC_STOP:
1253 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_STOP);
1254 break;
1255 case IDC_EJECT:
1256 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_EJECT);
1257 break;
1258 case IDC_BACKWARD:
1259 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_BACKWARD);
1260 break;
1261 case IDC_SEEKBACK:
1262 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_SEEKBACK);
1263 break;
1264 case IDC_SEEKFORW:
1265 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_SEEKFORW);
1266 break;
1267 case IDC_FORWARD:
1268 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_FORWARD);
1269 break;
1270 case IDC_PAUSE:
1271 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PAUSE);
1272 break;
1273 }
1274 break;
1275 }
1276 }
1277 }
1278 break;
1279
1280 case WM_SIZING:
1281 {
1282 LPRECT pRect = (LPRECT)lParam;
1283
1284 if (!bIsSingleWindow)
1285 {
1286 if (pRect->right - pRect->left < MAIN_WINDOW_MIN_WIDTH)
1287 pRect->right = pRect->left + MAIN_WINDOW_MIN_WIDTH;
1288
1289 if (pRect->bottom - pRect->top != MAIN_WINDOW_HEIGHT)
1290 pRect->bottom = pRect->top + MAIN_WINDOW_HEIGHT;
1291 }
1292 return TRUE;
1293 }
1294
1295 case WM_SIZE:
1296 {
1297 RECT Rect;
1298
1299 if (hToolBar && hTrackBar)
1300 {
1301 SendMessage(hToolBar, TB_AUTOSIZE, 0, 0);
1302 SendMessage(hToolBar, TB_GETITEMRECT, 1, (LPARAM)&Rect);
1303 MoveWindow(hTimeDisplay, LOWORD(lParam) - 140, 4, 135, 18, TRUE);
1304
1305 if (!bIsSingleWindow)
1306 {
1307 UINT Size = GetSystemMetrics(SM_CYMENU) + Rect.bottom;
1308 MoveWindow(hTrackBar, 0, 0, LOWORD(lParam), HIWORD(lParam) - Size, TRUE);
1309 }
1310 else
1311 {
1312 RECT ToolbarRect;
1313 MCI_DGV_PUT_PARMS mciPut;
1314
1315 MoveWindow(hTrackBar, 180, 0, LOWORD(lParam) - 322, 25, TRUE);
1316
1317 GetClientRect(hwnd, &Rect);
1318 GetClientRect(hToolBar, &ToolbarRect);
1319
1320 mciPut.rc.top = 0;
1321 mciPut.rc.left = 0;
1322 mciPut.rc.right = Rect.right;
1323 mciPut.rc.bottom = Rect.bottom - (ToolbarRect.bottom - ToolbarRect.top) - 2;
1324
1325 mciSendCommand(wDeviceId, MCI_PUT, MCI_DGV_PUT_DESTINATION | MCI_DGV_RECT | MCI_WAIT, (DWORD_PTR)&mciPut);
1326 }
1327 }
1328 return 0L;
1329 }
1330
1331 case WM_HSCROLL:
1332 {
1333 if (hTrackBar == (HWND)lParam)
1334 {
1335 if (wDeviceId)
1336 {
1337 DWORD dwNewPos = (DWORD)SendMessage(hTrackBar, TBM_GETPOS, 0, 0);
1338 SeekPlayback(hwnd, dwNewPos);
1339 }
1340 else
1341 {
1342 SendMessage(hTrackBar, TBM_SETPOS, TRUE, 0);
1343 }
1344 }
1345 }
1346 break;
1347
1348 case WM_NCLBUTTONDBLCLK:
1349 {
1350 if (wParam == HTCAPTION)
1351 {
1352 SwitchViewMode(hwnd);
1353 }
1354 }
1355 break;
1356
1357 case WM_COMMAND:
1358 {
1359 if (LOWORD(wParam) >= IDM_DEVICE_FIRST)
1360 {
1361 HandleDeviceMenuItem(hwnd, LOWORD(wParam));
1362 break;
1363 }
1364
1365 switch (LOWORD(wParam))
1366 {
1367 case IDC_PLAY:
1368 case IDC_PAUSE:
1369 {
1370 if (wDeviceId)
1371 TogglePlaybackState(hwnd);
1372 else
1373 OpenFileDialog(hwnd, 1, NULL);
1374
1375 break;
1376 }
1377
1378 case IDC_STOP:
1379 StopPlayback(hwnd);
1380 break;
1381
1382 case IDC_EJECT:
1383 break;
1384
1385 case IDC_BACKWARD:
1386 break;
1387
1388 case IDC_SEEKBACK:
1389 SeekBackPlayback(hwnd);
1390 break;
1391
1392 case IDC_SEEKFORW:
1393 SeekForwPlayback(hwnd);
1394 break;
1395
1396 case IDC_FORWARD:
1397 break;
1398
1399 case IDM_OPEN_FILE:
1400 OpenFileDialog(hwnd, 1, NULL);
1401 return 0;
1402
1403 case IDM_CLOSE_FILE:
1404 CloseMediaFile(hwnd);
1405 break;
1406
1407 case IDM_REPEAT:
1408 {
1409 if (!bRepeat)
1410 {
1411 CheckMenuItem(hMainMenu, IDM_REPEAT, MF_BYCOMMAND | MF_CHECKED);
1412 bRepeat = TRUE;
1413 }
1414 else
1415 {
1416 CheckMenuItem(hMainMenu, IDM_REPEAT, MF_BYCOMMAND | MF_UNCHECKED);
1417 bRepeat = FALSE;
1418 }
1419 break;
1420 }
1421
1422 case IDM_SWITCHVIEW:
1423 SwitchViewMode(hwnd);
1424 break;
1425
1426 case IDM_DEVPROPS:
1427 ShowDeviceProperties(hwnd);
1428 break;
1429
1430 case IDM_VOLUMECTL:
1431 ShellExecute(hwnd, NULL, _T("SNDVOL32.EXE"), NULL, NULL, SW_SHOWNORMAL);
1432 break;
1433
1434 case IDM_ABOUT:
1435 {
1436 HICON mplayIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN));
1437 ShellAbout(hwnd, szAppTitle, 0, mplayIcon);
1438 DeleteObject(mplayIcon);
1439 break;
1440 }
1441
1442 case IDM_EXIT:
1443 PostMessage(hwnd, WM_CLOSE, 0, 0);
1444 return 0;
1445 }
1446 break;
1447 }
1448
1449 case WM_DESTROY:
1450 CloseMediaFile(hwnd);
1451 PostQuitMessage(0);
1452 return 0;
1453 }
1454
1455 return DefWindowProc(hwnd, Message, wParam, lParam);
1456 }
1457
1458 INT WINAPI
1459 _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR lpCmdLine, INT nCmdShow)
1460 {
1461 WNDCLASSEX WndClass = {0};
1462 TCHAR szClassName[] = _T("ROSMPLAY32");
1463 HWND hwnd;
1464 MSG msg;
1465 DWORD dwError;
1466 HANDLE hAccel;
1467
1468 hInstance = hInst;
1469
1470 LoadString(hInstance, IDS_APPTITLE, szAppTitle, ARRAYSIZE(szAppTitle));
1471
1472 WndClass.cbSize = sizeof(WndClass);
1473 WndClass.lpszClassName = szClassName;
1474 WndClass.lpfnWndProc = MainWndProc;
1475 WndClass.hInstance = hInstance;
1476 WndClass.style = CS_HREDRAW | CS_VREDRAW;
1477 WndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN));
1478 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
1479 WndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1480 WndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU);
1481
1482 if (!RegisterClassEx(&WndClass))
1483 {
1484 ShowLastWin32Error(NULL);
1485 return 0;
1486 }
1487
1488 hwnd = CreateWindow(szClassName,
1489 szAppTitle,
1490 WS_SYSMENU | WS_MINIMIZEBOX | WS_THICKFRAME | WS_OVERLAPPED | WS_CAPTION | WS_CLIPCHILDREN,
1491 CW_USEDEFAULT,
1492 CW_USEDEFAULT,
1493 350,
1494 MAIN_WINDOW_HEIGHT,
1495 NULL,
1496 NULL,
1497 hInstance,
1498 NULL);
1499 if (!hwnd)
1500 {
1501 ShowLastWin32Error(NULL);
1502 return 0;
1503 }
1504
1505 hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(ID_ACCELERATORS));
1506
1507 BuildFileFilterAndDeviceMenu();
1508
1509 DragAcceptFiles(hwnd, TRUE);
1510
1511 DisableMenuItems();
1512
1513 dwError = SearchPath(NULL, _T("SNDVOL32.EXE"), NULL, 0, NULL, NULL);
1514 if (dwError == 0)
1515 {
1516 EnableMenuItem(hMainMenu, IDM_VOLUMECTL, MF_BYCOMMAND | MF_GRAYED);
1517 }
1518
1519 /* Show it */
1520 ShowWindow(hwnd, SW_SHOW);
1521 UpdateWindow(hwnd);
1522
1523 OpenMediaFile(hwnd, lpCmdLine, NULL);
1524
1525 /* Message Loop */
1526 while (GetMessage(&msg, NULL, 0, 0))
1527 {
1528 if (!TranslateAccelerator(hwnd, hAccel, &msg))
1529 {
1530 TranslateMessage(&msg);
1531 DispatchMessage(&msg);
1532 }
1533 }
1534
1535 CleanupFileFilter();
1536
1537 DestroyAcceleratorTable(hAccel);
1538
1539 return (INT)msg.wParam;
1540 }