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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1142 CleanupFileFilter(VOID) 1143 { 1144 if (szFilter && szFilter != szDefaultFilter) free(szFilter); 1145 } 1146 1147 static VOID 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 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 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 HICON mplayIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN)); 1443 ShellAbout(hwnd, szAppTitle, NULL, mplayIcon); 1444 DeleteObject(mplayIcon); 1445 break; 1446 } 1447 1448 case IDM_EXIT: 1449 PostMessage(hwnd, WM_CLOSE, 0, 0); 1450 return 0; 1451 } 1452 break; 1453 } 1454 1455 case WM_DESTROY: 1456 CloseMediaFile(hwnd); 1457 PostQuitMessage(0); 1458 return 0; 1459 } 1460 1461 return DefWindowProc(hwnd, Message, wParam, lParam); 1462 } 1463 1464 INT WINAPI 1465 _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR lpCmdLine, INT nCmdShow) 1466 { 1467 WNDCLASSEX WndClass = {0}; 1468 TCHAR szClassName[] = _T("ROSMPLAY32"); 1469 HWND hwnd; 1470 MSG msg; 1471 DWORD dwError; 1472 HANDLE hAccel; 1473 1474 hInstance = hInst; 1475 1476 switch (GetUserDefaultUILanguage()) 1477 { 1478 case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT): 1479 SetProcessDefaultLayout(LAYOUT_RTL); 1480 break; 1481 1482 default: 1483 break; 1484 } 1485 1486 LoadString(hInstance, IDS_APPTITLE, szAppTitle, ARRAYSIZE(szAppTitle)); 1487 1488 WndClass.cbSize = sizeof(WndClass); 1489 WndClass.lpszClassName = szClassName; 1490 WndClass.lpfnWndProc = MainWndProc; 1491 WndClass.hInstance = hInstance; 1492 WndClass.style = CS_HREDRAW | CS_VREDRAW; 1493 WndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN)); 1494 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); 1495 WndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 1496 WndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU); 1497 1498 if (!RegisterClassEx(&WndClass)) 1499 { 1500 ShowLastWin32Error(NULL); 1501 return 0; 1502 } 1503 1504 hwnd = CreateWindow(szClassName, 1505 szAppTitle, 1506 WS_SYSMENU | WS_MINIMIZEBOX | WS_THICKFRAME | WS_OVERLAPPED | WS_CAPTION | WS_CLIPCHILDREN, 1507 CW_USEDEFAULT, 1508 CW_USEDEFAULT, 1509 350, 1510 MAIN_WINDOW_HEIGHT, 1511 NULL, 1512 NULL, 1513 hInstance, 1514 NULL); 1515 if (!hwnd) 1516 { 1517 ShowLastWin32Error(NULL); 1518 return 0; 1519 } 1520 1521 hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(ID_ACCELERATORS)); 1522 1523 BuildFileFilterAndDeviceMenu(); 1524 1525 DragAcceptFiles(hwnd, TRUE); 1526 1527 DisableMenuItems(); 1528 1529 dwError = SearchPath(NULL, _T("SNDVOL32.EXE"), NULL, 0, NULL, NULL); 1530 if (dwError == 0) 1531 { 1532 EnableMenuItem(hMainMenu, IDM_VOLUMECTL, MF_BYCOMMAND | MF_GRAYED); 1533 } 1534 1535 /* Show it */ 1536 ShowWindow(hwnd, SW_SHOW); 1537 UpdateWindow(hwnd); 1538 1539 if (*lpCmdLine == _T('"')) 1540 { 1541 OpenMediaFile(hwnd, argv[1], NULL); 1542 } 1543 else 1544 { 1545 OpenMediaFile(hwnd, lpCmdLine, NULL); 1546 } 1547 1548 /* Message Loop */ 1549 while (GetMessage(&msg, NULL, 0, 0)) 1550 { 1551 if (!TranslateAccelerator(hwnd, hAccel, &msg)) 1552 { 1553 TranslateMessage(&msg); 1554 DispatchMessage(&msg); 1555 } 1556 } 1557 1558 CleanupFileFilter(); 1559 1560 DestroyAcceleratorTable(hAccel); 1561 1562 return (INT)msg.wParam; 1563 } 1564