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