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 } 1548