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