/* * PROJECT: ReactOS Multimedia Player * FILE: base/applications/mplay32/mplay32.c * PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org) */ #include "mplay32.h" #define IDT_PLAYTIMER 1000 #define MAIN_WINDOW_HEIGHT 125 #define MAIN_WINDOW_MIN_WIDTH 250 #define MAX_MCISTR 256 HINSTANCE hInstance = NULL; HWND hTrackBar = NULL; HWND hToolBar = NULL; HWND hTimeDisplay = NULL; HMENU hMainMenu = NULL; TCHAR szAppTitle[256] = _T(""); TCHAR szDefaultFilter[MAX_PATH] = _T(""); TCHAR szCurrentFile[MAX_PATH] = _T(""); LPTSTR szFilter = NULL; WORD wDeviceId = 0; BOOL bRepeat = FALSE; BOOL bIsSingleWindow = FALSE; UINT MaxFilePos = 0; RECT PrevWindowPos; static DWORD GetDeviceMode(HWND hwnd); /* ToolBar Buttons */ static const TBBUTTON Buttons[] = { /* iBitmap, idCommand, fsState, fsStyle, bReserved[2], dwData, iString */ {TBICON_PLAY, IDC_PLAY, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, {TBICON_STOP, IDC_STOP, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, {TBICON_EJECT, IDC_EJECT, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0}, {TBICON_BACKWARD, IDC_BACKWARD, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, {TBICON_SEEKBACK, IDC_SEEKBACK, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, {TBICON_SEEKFORW, IDC_SEEKFORW, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, {TBICON_FORWARD, IDC_FORWARD, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, // {TBICON_PAUSE, IDC_PAUSE, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0} }; void EnableMenuItems(HWND hwnd) { MCIERROR mciError; MCI_GENERIC_PARMS mciGeneric; MCI_DGV_RECT_PARMS mciVideoRect; MCI_DGV_WINDOW_PARMSW mciVideoWindow; EnableMenuItem(hMainMenu, IDM_CLOSE_FILE, MF_BYCOMMAND | MF_ENABLED); mciError = mciSendCommand(wDeviceId, MCI_CONFIGURE, MCI_TEST, (DWORD_PTR)&mciGeneric); if (mciError == 0) { EnableMenuItem(hMainMenu, IDM_DEVPROPS, MF_BYCOMMAND | MF_ENABLED); } mciVideoWindow.hWnd = hwnd; mciError = mciSendCommand(wDeviceId, MCI_WINDOW, MCI_DGV_WINDOW_HWND | MCI_TEST, (DWORD_PTR)&mciVideoWindow); if (!mciError) { mciError = mciSendCommand(wDeviceId, MCI_WHERE, MCI_DGV_WHERE_SOURCE | MCI_TEST, (DWORD_PTR)&mciVideoRect); if (!mciError) { EnableMenuItem(hMainMenu, IDM_SWITCHVIEW, MF_BYCOMMAND | MF_ENABLED); } } } void DisableMenuItems(void) { EnableMenuItem(hMainMenu, IDM_CLOSE_FILE, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(hMainMenu, IDM_DEVPROPS, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(hMainMenu, IDM_SWITCHVIEW, MF_BYCOMMAND | MF_GRAYED); } void ResizeClientArea(HWND hwnd, int nWidth, int nHeight) { RECT rcClientRect; RECT rcWindowRect; POINT ptDifference; GetClientRect(hwnd, &rcClientRect); GetWindowRect(hwnd, &rcWindowRect); ptDifference.x = (rcWindowRect.right - rcWindowRect.left) - rcClientRect.right; ptDifference.y = (rcWindowRect.bottom - rcWindowRect.top) - rcClientRect.bottom; MoveWindow(hwnd, rcWindowRect.left, rcWindowRect.top, nWidth + ptDifference.x, nHeight + ptDifference.y, TRUE); } void UpdateWindowCaption(HWND hwnd) { TCHAR szNewTitle[MAX_PATH + 3 + 256]; TCHAR szStatus[128]; if (wDeviceId == 0) { SetWindowText(hwnd, szAppTitle); return; } switch (GetDeviceMode(hwnd)) { case MCI_MODE_PAUSE: { LoadString(hInstance, IDS_MODE_PAUSE, szStatus, ARRAYSIZE(szStatus)); break; } case MCI_MODE_STOP: { LoadString(hInstance, IDS_MODE_STOP, szStatus, ARRAYSIZE(szStatus)); break; } case MCI_MODE_PLAY: { LoadString(hInstance, IDS_MODE_PLAY, szStatus, ARRAYSIZE(szStatus)); break; } case MCI_MODE_OPEN: { LoadString(hInstance, IDS_MODE_OPEN, szStatus, ARRAYSIZE(szStatus)); break; } case MCI_MODE_RECORD: { LoadString(hInstance, IDS_MODE_RECORD, szStatus, ARRAYSIZE(szStatus)); break; } case MCI_MODE_SEEK: { LoadString(hInstance, IDS_MODE_SEEK, szStatus, ARRAYSIZE(szStatus)); break; } case MCI_MODE_NOT_READY: { LoadString(hInstance, IDS_MODE_NOT_READY, szStatus, ARRAYSIZE(szStatus)); break; } default: { LoadString(hInstance, IDS_MODE_UNKNOWN, szStatus, ARRAYSIZE(szStatus)); } } StringCbPrintf(szNewTitle, sizeof(szNewTitle), _T("%s - %s (%s)"), szAppTitle, szCurrentFile, szStatus); SetWindowText(hwnd, szNewTitle); } void UpdateTimeDisplay(HWND hwnd) { MCI_STATUS_PARMS mciStatus; TCHAR szTime[MAX_MCISTR]; DWORD dwTimeFormat; if (!wDeviceId) { SetWindowText(hwnd, _T("")); return; } mciStatus.dwItem = MCI_STATUS_TIME_FORMAT; mciStatus.dwReturn = 0; mciSendCommand(wDeviceId, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus); dwTimeFormat = mciStatus.dwReturn; mciStatus.dwItem = MCI_STATUS_POSITION; mciStatus.dwReturn = 0; mciSendCommand(wDeviceId, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus); switch(dwTimeFormat) { case MCI_FORMAT_MILLISECONDS: { int s, m, h; s = (mciStatus.dwReturn / 1000) % 60; m = ((mciStatus.dwReturn / (1000*60)) % 60); h = ((mciStatus.dwReturn / (1000*60*60)) % 24); StringCbPrintf(szTime, sizeof(szTime), _T("%02lu:%02lu:%02lu"), h, m, s); break; } /* The time format is unknown, so use the returned position as is */ default: { StringCbPrintf(szTime, sizeof(szTime), _T("%lu"), mciStatus.dwReturn); break; } } SetWindowText(hwnd, szTime); } static VOID ShowLastWin32Error(HWND hwnd) { LPTSTR lpMessageBuffer; DWORD dwError = GetLastError(); if (dwError == ERROR_SUCCESS) return; if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, LANG_USER_DEFAULT, (LPTSTR)&lpMessageBuffer, 0, NULL)) { return; } MessageBox(hwnd, lpMessageBuffer, szAppTitle, MB_OK | MB_ICONERROR); LocalFree(lpMessageBuffer); } static VOID SetImageList(HWND hwnd) { HIMAGELIST hImageList; hImageList = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR24, 1, 1); if (!hImageList) { ShowLastWin32Error(hwnd); return; } ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_PLAYICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR), RGB(255, 255, 255)); ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_STOPICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR), RGB(255, 255, 255)); ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_EJECTICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR), RGB(255, 255, 255)); ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_BACKWARDICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR), RGB(255, 255, 255)); ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_SEEKBACKICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR), RGB(255, 255, 255)); ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_SEEKFORWICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR), RGB(255, 255, 255)); ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_FORWARDICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR), RGB(255, 255, 255)); ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_PAUSEICON), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR), RGB(255, 255, 255)); ImageList_Destroy((HIMAGELIST)SendMessage(hToolBar, TB_SETIMAGELIST, 0, (LPARAM)hImageList)); } static VOID ShowMCIError(HWND hwnd, MCIERROR mciError) { TCHAR szErrorMessage[MAX_MCISTR]; TCHAR szTempMessage[MAX_MCISTR + 44]; if (mciGetErrorString(mciError, szErrorMessage, ARRAYSIZE(szErrorMessage)) == FALSE) { LoadString(hInstance, IDS_DEFAULTMCIERRMSG, szErrorMessage, ARRAYSIZE(szErrorMessage)); } StringCbPrintf(szTempMessage, sizeof(szTempMessage), _T("MMSYS%lu: %s"), mciError, szErrorMessage); MessageBox(hwnd, szTempMessage, szAppTitle, MB_OK | MB_ICONEXCLAMATION); } static VOID InitControls(HWND hwnd) { INT NumButtons = ARRAYSIZE(Buttons); InitCommonControls(); /* Create trackbar */ hTrackBar = CreateWindowEx(0, TRACKBAR_CLASS, NULL, TBS_ENABLESELRANGE | WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPSIBLINGS, 0, 0, 340, 20, hwnd, NULL, hInstance, NULL); if (!hTrackBar) { ShowLastWin32Error(hwnd); return; } /* Create toolbar */ hToolBar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPSIBLINGS | TBSTYLE_FLAT | CCS_BOTTOM | TBSTYLE_TOOLTIPS, 0, 40, 340, 30, hwnd, NULL, hInstance, NULL); if (!hToolBar) { ShowLastWin32Error(hwnd); return; } hTimeDisplay = CreateWindowEx(0, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | SS_CENTER | SS_SUNKEN, 195, 4, 135, 18, hToolBar, NULL, hInstance, NULL); if (!hTimeDisplay) { ShowLastWin32Error(hwnd); return; } SetImageList(hwnd); SendMessage(hToolBar, TB_ADDBUTTONS, NumButtons, (LPARAM)Buttons); } static VOID SwitchViewMode(HWND hwnd) { MCIERROR mciError; MCI_DGV_RECT_PARMS mciVideoRect; MCI_DGV_WINDOW_PARMSW mciVideoWindow; RECT rcToolbarRect; RECT rcTempRect; mciVideoWindow.hWnd = hwnd; mciError = mciSendCommand(wDeviceId, MCI_WINDOW, MCI_DGV_WINDOW_HWND | MCI_TEST, (DWORD_PTR)&mciVideoWindow); if (mciError != 0) return; mciError = mciSendCommand(wDeviceId, MCI_WHERE, MCI_DGV_WHERE_SOURCE | MCI_TEST, (DWORD_PTR)&mciVideoRect); if (mciError != 0) return; if (!bIsSingleWindow) { GetWindowRect(hwnd, &PrevWindowPos); SetParent(hTrackBar, hToolBar); mciError = mciSendCommand(wDeviceId, MCI_WHERE, MCI_DGV_WHERE_SOURCE, (DWORD_PTR)&mciVideoRect); if (mciError != 0) { ShowMCIError(hwnd, mciError); return; } GetWindowRect(hToolBar, &rcToolbarRect); ResizeClientArea(hwnd, mciVideoRect.rc.right, mciVideoRect.rc.bottom + (rcToolbarRect.bottom - rcToolbarRect.top)); mciError = mciSendCommand(wDeviceId, MCI_WINDOW, MCI_DGV_WINDOW_HWND, (DWORD_PTR)&mciVideoWindow); if (mciError != 0) { ShowMCIError(hwnd, mciError); return; } GetWindowRect(hToolBar, &rcTempRect); MoveWindow(hTrackBar, 180, 0, rcTempRect.right - rcTempRect.left - 322, 25, TRUE); MoveWindow(hTimeDisplay, rcTempRect.right - rcTempRect.left - 140, 4, 135, 18, TRUE); CheckMenuItem(hMainMenu, IDM_SWITCHVIEW, MF_BYCOMMAND | MF_CHECKED); bIsSingleWindow = TRUE; } else { bIsSingleWindow = FALSE; CheckMenuItem(hMainMenu, IDM_SWITCHVIEW, MF_BYCOMMAND | MF_UNCHECKED); mciVideoWindow.hWnd = MCI_DGV_WINDOW_DEFAULT; mciError = mciSendCommand(wDeviceId, MCI_WINDOW, MCI_DGV_WINDOW_HWND, (DWORD_PTR)&mciVideoWindow); if (mciError != 0) { ShowMCIError(hwnd, mciError); return; } SetParent(hTrackBar, hwnd); MoveWindow(hwnd, PrevWindowPos.left, PrevWindowPos.top, PrevWindowPos.right - PrevWindowPos.left, PrevWindowPos.bottom - PrevWindowPos.top, TRUE); } } static DWORD GetNumDevices(VOID) { MCI_SYSINFO_PARMS mciSysInfo; DWORD dwNumDevices = 0; mciSysInfo.dwCallback = 0; mciSysInfo.lpstrReturn = (LPTSTR)&dwNumDevices; mciSysInfo.dwRetSize = sizeof(dwNumDevices); mciSysInfo.dwNumber = 0; mciSysInfo.wDeviceType = MCI_ALL_DEVICE_ID; mciSendCommand(MCI_ALL_DEVICE_ID, MCI_SYSINFO, MCI_SYSINFO_QUANTITY, (DWORD_PTR)&mciSysInfo); return *(DWORD*)mciSysInfo.lpstrReturn; } static DWORD GetDeviceName(DWORD dwDeviceIndex, LPTSTR lpDeviceName, DWORD dwDeviceNameSize) { MCI_SYSINFO_PARMS mciSysInfo; mciSysInfo.dwCallback = 0; mciSysInfo.lpstrReturn = lpDeviceName; mciSysInfo.dwRetSize = dwDeviceNameSize; mciSysInfo.dwNumber = dwDeviceIndex; mciSysInfo.wDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO; return mciSendCommand(MCI_ALL_DEVICE_ID, MCI_SYSINFO, MCI_SYSINFO_NAME, (DWORD_PTR)&mciSysInfo); } static DWORD GetDeviceFriendlyName(LPTSTR lpDeviceName, LPTSTR lpFriendlyName, DWORD dwFriendlyNameSize) { MCIERROR mciError; MCI_OPEN_PARMS mciOpen; MCI_INFO_PARMS mciInfo; MCI_GENERIC_PARMS mciGeneric; mciOpen.dwCallback = 0; mciOpen.wDeviceID = 0; mciOpen.lpstrDeviceType = lpDeviceName; mciOpen.lpstrElementName = NULL; mciOpen.lpstrAlias = NULL; mciError = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_WAIT, (DWORD_PTR)&mciOpen); if (mciError != 0) return mciError; mciInfo.dwCallback = 0; mciInfo.lpstrReturn = lpFriendlyName; mciInfo.dwRetSize = dwFriendlyNameSize; mciError = mciSendCommand(mciOpen.wDeviceID, MCI_INFO, MCI_INFO_PRODUCT, (DWORD_PTR)&mciInfo); mciGeneric.dwCallback = 0; mciSendCommand(mciOpen.wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)&mciGeneric); return mciError; } static BOOL DeviceUsesFiles(LPTSTR lpDeviceName) { MCIERROR mciError; MCI_OPEN_PARMS mciOpen; MCI_GETDEVCAPS_PARMS mciDevCaps; MCI_GENERIC_PARMS mciGeneric; mciOpen.dwCallback = 0; mciOpen.wDeviceID = 0; mciOpen.lpstrDeviceType = lpDeviceName; mciOpen.lpstrElementName = NULL; mciOpen.lpstrAlias = NULL; mciError = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_WAIT, (DWORD_PTR)&mciOpen); if (mciError != 0) return FALSE; mciDevCaps.dwCallback = 0; mciDevCaps.dwReturn = 0; mciDevCaps.dwItem = MCI_GETDEVCAPS_USES_FILES; mciError = mciSendCommand(mciOpen.wDeviceID, MCI_GETDEVCAPS, MCI_WAIT | MCI_GETDEVCAPS_ITEM, (DWORD_PTR)&mciDevCaps); if (mciError != 0) return FALSE; mciGeneric.dwCallback = 0; mciSendCommand(mciOpen.wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)&mciGeneric); return (BOOL)mciDevCaps.dwReturn; } static MCIERROR CloseMciDevice(VOID) { MCIERROR mciError; MCI_GENERIC_PARMS mciGeneric; if (wDeviceId) { mciError = mciSendCommand(wDeviceId, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)&mciGeneric); if (mciError != 0) return mciError; wDeviceId = 0; } UpdateTimeDisplay(hTimeDisplay); DisableMenuItems(); return 0; } static MCIERROR OpenMciDevice(HWND hwnd, LPTSTR lpType, LPTSTR lpFileName) { MCIERROR mciError; MCI_STATUS_PARMS mciStatus; MCI_OPEN_PARMS mciOpen; DWORD dwFlags = MCI_WAIT; LPTSTR lpStr; if (wDeviceId) CloseMciDevice(); mciOpen.lpstrDeviceType = lpType; mciOpen.lpstrElementName = lpFileName; mciOpen.dwCallback = 0; mciOpen.wDeviceID = 0; mciOpen.lpstrAlias = NULL; if (lpType) dwFlags |= MCI_OPEN_TYPE; if (lpFileName) dwFlags |= MCI_OPEN_ELEMENT; mciError = mciSendCommand(0, MCI_OPEN, dwFlags, (DWORD_PTR)&mciOpen); if (mciError != 0) return mciError; mciStatus.dwItem = MCI_STATUS_LENGTH; mciError = mciSendCommand(mciOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&mciStatus); if (mciError != 0) return mciError; SendMessage(hTrackBar, TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)1); SendMessage(hTrackBar, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)mciStatus.dwReturn); SendMessage(hTrackBar, TBM_SETPAGESIZE, 0, 10); SendMessage(hTrackBar, TBM_SETLINESIZE, 0, 1); SendMessage(hTrackBar, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)1); if (mciStatus.dwReturn < 10000) { SendMessage(hTrackBar, TBM_SETTICFREQ, (WPARAM)100, (LPARAM)0); } else if (mciStatus.dwReturn < 100000) { SendMessage(hTrackBar, TBM_SETTICFREQ, (WPARAM)1000, (LPARAM)0); } else if (mciStatus.dwReturn < 1000000) { SendMessage(hTrackBar, TBM_SETTICFREQ, (WPARAM)10000, (LPARAM)0); } else { SendMessage(hTrackBar, TBM_SETTICFREQ, (WPARAM)100000, (LPARAM)0); } MaxFilePos = mciStatus.dwReturn; wDeviceId = mciOpen.wDeviceID; /* NOTE: Everything above this line may be done instead in OpenMediaFile() */ if (lpFileName) { lpStr = _tcsrchr(lpFileName, _T('\\')); if (lpStr) // Get only the file name (skip the last path separator) lpStr++; else lpStr = lpFileName; } else lpStr = lpType; StringCbCopy(szCurrentFile, sizeof(szCurrentFile), lpStr); EnableMenuItems(hwnd); UpdateTimeDisplay(hTimeDisplay); UpdateWindowCaption(hwnd); return 0; } static DWORD GetDeviceMode(HWND hwnd) { MCIERROR mciError; MCI_STATUS_PARMS mciStatus; mciStatus.dwItem = MCI_STATUS_MODE; mciError = mciSendCommand(wDeviceId, MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus); if (mciError != 0) { ShowMCIError(hwnd, mciError); return MCI_MODE_NOT_READY; } return mciStatus.dwReturn; } static VOID StopPlayback(HWND hwnd) { MCIERROR mciError; MCI_GENERIC_PARMS mciGeneric; MCI_SEEK_PARMS mciSeek; if (wDeviceId == 0) return; KillTimer(hwnd, IDT_PLAYTIMER); SendMessage(hTrackBar, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)1); mciGeneric.dwCallback = (DWORD_PTR)hwnd; mciError = mciSendCommand(wDeviceId, MCI_STOP, MCI_WAIT, (DWORD_PTR)&mciGeneric); if (mciError != 0) { ShowMCIError(hwnd, mciError); return; } mciSendCommand(wDeviceId, MCI_SEEK, MCI_WAIT | MCI_SEEK_TO_START, (DWORD_PTR)&mciSeek); UpdateTimeDisplay(hTimeDisplay); UpdateWindowCaption(hwnd); SendMessage(hToolBar, TB_SETCMDID, 0, IDC_PLAY); SendMessage(hToolBar, TB_CHANGEBITMAP, IDC_PLAY, IDB_PLAYICON - IDB_PLAYICON); } static VOID SeekPlayback(HWND hwnd, DWORD dwNewPos) { MCIERROR mciError; MCI_SEEK_PARMS mciSeek; MCI_PLAY_PARMS mciPlay; if (wDeviceId == 0) return; mciSeek.dwTo = (DWORD_PTR)dwNewPos; mciError = mciSendCommand(wDeviceId, MCI_SEEK, MCI_WAIT | MCI_TO, (DWORD_PTR)&mciSeek); if (mciError != 0) { ShowMCIError(hwnd, mciError); } mciPlay.dwCallback = (DWORD_PTR)hwnd; mciError = mciSendCommand(wDeviceId, MCI_PLAY, MCI_NOTIFY, (DWORD_PTR)&mciPlay); if (mciError != 0) { ShowMCIError(hwnd, mciError); } } static VOID SeekBackPlayback(HWND hwnd) { MCI_STATUS_PARMS mciStatus; DWORD dwNewPos; if (wDeviceId == 0) return; mciStatus.dwItem = MCI_STATUS_POSITION; mciSendCommand(wDeviceId, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus); dwNewPos = mciStatus.dwReturn - 1; if ((UINT)dwNewPos <= 1) { StopPlayback(hwnd); } else { SeekPlayback(hwnd, dwNewPos); } } static VOID SeekForwPlayback(HWND hwnd) { MCI_STATUS_PARMS mciStatus; DWORD dwNewPos; if (wDeviceId == 0) return; mciStatus.dwItem = MCI_STATUS_POSITION; mciSendCommand(wDeviceId, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus); dwNewPos = mciStatus.dwReturn + 1; if ((UINT)dwNewPos >= MaxFilePos) { StopPlayback(hwnd); } else { SeekPlayback(hwnd, dwNewPos); } } VOID CALLBACK PlayTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { MCI_STATUS_PARMS mciStatus; DWORD dwPos; if (wDeviceId == 0) KillTimer(hwnd, IDT_PLAYTIMER); mciStatus.dwItem = MCI_STATUS_POSITION; mciSendCommand(wDeviceId, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus); dwPos = mciStatus.dwReturn; SendMessage(hTrackBar, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)dwPos); UpdateTimeDisplay(hTimeDisplay); } static VOID StartPlayback(HWND hwnd) { MCIERROR mciError; MCI_PLAY_PARMS mciPlay; MCI_SEEK_PARMS mciSeek; SetTimer(hwnd, IDT_PLAYTIMER, 100, (TIMERPROC)PlayTimerProc); mciSendCommand(wDeviceId, MCI_SEEK, MCI_WAIT | MCI_SEEK_TO_START, (DWORD_PTR)&mciSeek); mciPlay.dwCallback = (DWORD_PTR)hwnd; mciPlay.dwFrom = 0; mciPlay.dwTo = MaxFilePos; mciError = mciSendCommand(wDeviceId, MCI_PLAY, MCI_NOTIFY | MCI_FROM /*| MCI_TO*/, (DWORD_PTR)&mciPlay); if (mciError != 0) { ShowMCIError(hwnd, mciError); return; } UpdateWindowCaption(hwnd); SendMessage(hToolBar, TB_SETCMDID, 0, IDC_PAUSE); SendMessage(hToolBar, TB_CHANGEBITMAP, IDC_PAUSE, IDB_PAUSEICON - IDB_PLAYICON); } static VOID TogglePlaybackState(HWND hwnd) { MCIERROR mciError; MCI_GENERIC_PARMS mciGeneric; ULONG idBmp = IDB_PLAYICON; ULONG idCmd = IDC_PLAY; if (wDeviceId == 0) return; switch (GetDeviceMode(hwnd)) { case MCI_MODE_OPEN: case MCI_MODE_STOP: { StartPlayback(hwnd); return; } case MCI_MODE_PLAY: { mciGeneric.dwCallback = (DWORD_PTR)hwnd; mciError = mciSendCommand(wDeviceId, MCI_PAUSE, MCI_WAIT, (DWORD_PTR)&mciGeneric); idBmp = IDB_PLAYICON; idCmd = IDC_PLAY; break; } case MCI_MODE_PAUSE: { mciGeneric.dwCallback = (DWORD_PTR)hwnd; mciError = mciSendCommand(wDeviceId, MCI_RESUME, MCI_WAIT, (DWORD_PTR)&mciGeneric); idBmp = IDB_PAUSEICON; idCmd = IDC_PAUSE; break; } default: { return; } } if (mciError != 0) { ShowMCIError(hwnd, mciError); return; } UpdateWindowCaption(hwnd); SendMessage(hToolBar, TB_SETCMDID, 0, idCmd); SendMessage(hToolBar, TB_CHANGEBITMAP, idCmd, idBmp - IDB_PLAYICON); } static VOID ShowDeviceProperties(HWND hwnd) { MCIERROR mciError; MCI_GENERIC_PARMS mciGeneric; mciError = mciSendCommand(wDeviceId, MCI_CONFIGURE, MCI_WAIT, (DWORD_PTR)&mciGeneric); if (mciError != 0) { ShowMCIError(hwnd, mciError); } } static VOID CloseMediaFile(HWND hwnd) { StopPlayback(hwnd); if (bIsSingleWindow) SwitchViewMode(hwnd); CloseMciDevice(); UpdateWindowCaption(hwnd); } static VOID OpenMediaFile(HWND hwnd, LPTSTR lpFileName, LPTSTR lpType) { MCIERROR mciError; if (GetFileAttributes(lpFileName) == INVALID_FILE_ATTRIBUTES) return; if (wDeviceId) CloseMediaFile(hwnd); mciError = OpenMciDevice(hwnd, lpType, lpFileName); if (mciError != 0) { ShowMCIError(hwnd, mciError); return; } StartPlayback(hwnd); } static DWORD InsertDeviceMenuItem(HMENU hMenu, UINT uItem, BOOL fByPosition, UINT uItemID, DWORD dwDeviceIndex) { MENUITEMINFO lpmii; MCIERROR mciError; TCHAR szDeviceName[MAX_MCISTR]; TCHAR szFriendlyName[MAX_MCISTR]; mciError = GetDeviceName(dwDeviceIndex, szDeviceName, sizeof(szDeviceName)); if (mciError) { return mciError; } mciError = GetDeviceFriendlyName(szDeviceName, szFriendlyName, sizeof(szFriendlyName)); if (mciError) { return mciError; } if (DeviceUsesFiles(szDeviceName)) { StringCbCat(szFriendlyName, sizeof(szFriendlyName), _T("...")); } ZeroMemory(&lpmii, sizeof(MENUITEMINFO)); lpmii.cbSize = sizeof(lpmii); lpmii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID; lpmii.wID = uItemID; lpmii.fType = MF_STRING; lpmii.dwTypeData = szFriendlyName; lpmii.dwItemData = dwDeviceIndex; InsertMenuItem(hMenu, uItem, fByPosition, &lpmii); return 0; } static VOID BuildFileFilterAndDeviceMenu(VOID) { TCHAR szDeviceName[MAX_MCISTR]; TCHAR szFriendlyName[MAX_MCISTR]; TCHAR *szDevice = NULL; static TCHAR szDefaultExtension[] = _T("*.*"); TCHAR *szExtensionList = NULL; TCHAR *szExtension = NULL; TCHAR *c = NULL; TCHAR *d = NULL; DWORD dwNumValues; DWORD dwNumDevices; DWORD dwValueNameLen; DWORD dwValueDataSize; DWORD dwMaskLen; DWORD dwFilterSize; DWORD dwDeviceSize; DWORD dwExtensionLen; DWORD dwPosition = 0; DWORD i; DWORD j; UINT uSizeRemain; UINT uMaskRemain; HKEY hKey = NULL; /* Always load the default (all files) filter */ LoadString(hInstance, IDS_ALL_TYPES_FILTER, szDefaultFilter, ARRAYSIZE(szDefaultFilter)); if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\MCI Extensions"), 0, KEY_READ, &hKey) != ERROR_SUCCESS) { goto Failure; } if (RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwNumValues, &dwValueNameLen, &dwValueDataSize, NULL, NULL) != ERROR_SUCCESS) { goto Failure; } dwMaskLen = ((dwValueNameLen + 3) * dwNumValues) + 1; szExtensionList = malloc(dwMaskLen * sizeof(TCHAR)); if (!szExtensionList) goto Failure; dwNumDevices = GetNumDevices(); /* Allocate space for every pair of Device and Extension Filter */ dwFilterSize = (MAX_MCISTR + (dwMaskLen * 2) + 5) * dwNumDevices; /* Add space for the "All supported" entry */ dwFilterSize = (dwFilterSize + (dwMaskLen * 2) + 7) * sizeof(TCHAR) + sizeof(szDefaultFilter); szFilter = malloc(dwFilterSize); if (!szFilter) goto Failure; szExtension = malloc((dwValueNameLen + 1) * sizeof(TCHAR)); if (!szExtension) goto Failure; szDevice = malloc(dwValueDataSize + sizeof(TCHAR)); if (!szDevice) goto Failure; ZeroMemory(szFilter, dwFilterSize); uSizeRemain = dwFilterSize; c = szFilter; for (j = 1; j <= dwNumDevices; j++) { if (GetDeviceName(j, szDeviceName, sizeof(szDeviceName))) { continue; } if (GetDeviceFriendlyName(szDeviceName, szFriendlyName, sizeof(szFriendlyName))) { continue; } /* Insert a menu item under the "Device" menu for every found MCI device */ InsertDeviceMenuItem(GetSubMenu(hMainMenu, 3), dwPosition, TRUE, IDM_DEVICE_FIRST + dwPosition, j); dwPosition++; /* Copy the default extension list, that may be overwritten after... */ StringCbCopy(szExtensionList, dwMaskLen * sizeof(TCHAR), szDefaultExtension); /* Try to determine the real extension list */ uMaskRemain = dwMaskLen * sizeof(TCHAR); d = szExtensionList; for (i = 0; i < dwNumValues; i++) { dwExtensionLen = dwValueNameLen + 1; dwDeviceSize = dwValueDataSize + sizeof(TCHAR); ZeroMemory(szDevice, dwDeviceSize); if (RegEnumValue(hKey, i, szExtension, &dwExtensionLen, NULL, NULL, (LPBYTE)szDevice, &dwDeviceSize) == ERROR_SUCCESS) { CharLowerBuff(szDevice, dwDeviceSize / sizeof(TCHAR)); CharLowerBuff(szDeviceName, ARRAYSIZE(szDeviceName)); if (_tcscmp(szDeviceName, szDevice) == 0) { CharLowerBuff(szExtension, dwExtensionLen); StringCbPrintfEx(d, uMaskRemain, &d, &uMaskRemain, 0, _T("%s%s%s"), _T("*."), szExtension, _T(";")); } } } /* Remove the last separator */ d--; uSizeRemain += sizeof(*d); *d = _T('\0'); /* Add the description */ StringCbPrintfEx(c, uSizeRemain, &c, &uSizeRemain, 0, _T("%s (%s)"), szFriendlyName, szExtensionList); /* Skip one char to separate the description from the filter mask */ c++; uSizeRemain -= sizeof(*c); /* Append the filter mask */ StringCbCopyEx(c, uSizeRemain, szExtensionList, &c, &uSizeRemain, 0); /* Skip another char to separate the elements of the filter mask */ c++; uSizeRemain -= sizeof(*c); } /* Build the full list of supported extensions */ uMaskRemain = dwMaskLen * sizeof(TCHAR); d = szExtensionList; for (i = 0; i < dwNumValues; i++) { dwExtensionLen = dwValueNameLen + 1; if (RegEnumValue(hKey, i, szExtension, &dwExtensionLen, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { CharLowerBuff(szExtension, dwExtensionLen); StringCbPrintfEx(d, uMaskRemain, &d, &uMaskRemain, 0, _T("%s%s%s"), _T("*."), szExtension, _T(";")); } } /* Remove the last separator */ d--; uSizeRemain += sizeof(*d); *d = _T('\0'); /* Add the default (all files) description */ StringCbPrintfEx(c, uSizeRemain, &c, &uSizeRemain, 0, _T("%s (%s)"), szDefaultFilter, szExtensionList); /* Skip one char to separate the description from the filter mask */ c++; uSizeRemain -= sizeof(*c); /* Append the filter mask */ StringCbCopyEx(c, uSizeRemain, szExtensionList, &c, &uSizeRemain, 0); Cleanup: if (szExtensionList) free(szExtensionList); if (szExtension) free(szExtension); if (szDevice) free(szDevice); RegCloseKey(hKey); return; Failure: /* We failed at retrieving the supported files, so use the default filter */ if (szFilter) free(szFilter); szFilter = szDefaultFilter; uSizeRemain = sizeof(szDefaultFilter); c = szFilter; /* Add the default (all files) description */ StringCbPrintfEx(c, uSizeRemain, &c, &uSizeRemain, 0, _T("%s (%s)"), szDefaultFilter, szDefaultExtension); /* Skip one char to separate the description from the filter mask */ c++; uSizeRemain -= sizeof(*c); /* Append the filter mask */ StringCbCopyEx(c, uSizeRemain, szDefaultExtension, &c, &uSizeRemain, 0); goto Cleanup; } static VOID CleanupFileFilter(VOID) { if (szFilter && szFilter != szDefaultFilter) free(szFilter); } static VOID OpenFileDialog(HWND hwnd, DWORD dwFilterIndex, LPTSTR lpType) { OPENFILENAME OpenFileName; TCHAR szFile[MAX_PATH + 1] = _T(""); TCHAR szCurrentDir[MAX_PATH]; ZeroMemory(&OpenFileName, sizeof(OpenFileName)); if (!GetCurrentDirectory(ARRAYSIZE(szCurrentDir), szCurrentDir)) { StringCbCopy(szCurrentDir, sizeof(szCurrentDir), _T("c:\\")); } OpenFileName.lStructSize = sizeof(OpenFileName); OpenFileName.hwndOwner = hwnd; OpenFileName.hInstance = hInstance; OpenFileName.lpstrFilter = szFilter; OpenFileName.lpstrFile = szFile; OpenFileName.nMaxFile = ARRAYSIZE(szFile); OpenFileName.lpstrInitialDir = szCurrentDir; OpenFileName.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_SHAREAWARE; OpenFileName.lpstrDefExt = _T("\0"); OpenFileName.nFilterIndex = dwFilterIndex; if (!GetOpenFileName(&OpenFileName)) return; OpenMediaFile(hwnd, OpenFileName.lpstrFile, lpType); } static VOID HandleDeviceMenuItem(HWND hwnd, UINT uItem) { MENUITEMINFO lpmii; TCHAR szDeviceName[MAX_MCISTR]; MCIERROR mciError; ZeroMemory(&lpmii, sizeof(MENUITEMINFO)); lpmii.cbSize = sizeof(lpmii); lpmii.fMask = MIIM_DATA; GetMenuItemInfo(hMainMenu, uItem, FALSE, &lpmii); mciError = GetDeviceName(lpmii.dwItemData, szDeviceName, sizeof(szDeviceName)); if (mciError) { ShowMCIError(hwnd, mciError); return; } if (DeviceUsesFiles(szDeviceName)) { OpenFileDialog(hwnd, uItem - IDM_DEVICE_FIRST + 1, szDeviceName); return; } mciError = OpenMciDevice(hwnd, szDeviceName, NULL); if (mciError) { ShowMCIError(hwnd, mciError); } return; } LRESULT CALLBACK MainWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { switch (Message) { case WM_CREATE: { InitControls(hwnd); hMainMenu = GetMenu(hwnd); break; } case WM_DROPFILES: { HDROP drophandle; TCHAR droppedfile[MAX_PATH]; drophandle = (HDROP)wParam; DragQueryFile(drophandle, 0, droppedfile, ARRAYSIZE(droppedfile)); DragFinish(drophandle); OpenMediaFile(hwnd, droppedfile, NULL); break; } case MM_MCINOTIFY: { if (wParam == MCI_NOTIFY_SUCCESSFUL) { StopPlayback(hwnd); if (bRepeat) { StartPlayback(hwnd); } } break; } case WM_NOTIFY: { LPNMHDR pnmhdr = (LPNMHDR)lParam; switch (pnmhdr->code) { case TTN_GETDISPINFO: { LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)lParam; UINT idButton = (UINT)lpttt->hdr.idFrom; switch (idButton) { case IDC_PLAY: lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PLAY); break; case IDC_STOP: lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_STOP); break; case IDC_EJECT: lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_EJECT); break; case IDC_BACKWARD: lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_BACKWARD); break; case IDC_SEEKBACK: lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_SEEKBACK); break; case IDC_SEEKFORW: lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_SEEKFORW); break; case IDC_FORWARD: lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_FORWARD); break; case IDC_PAUSE: lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PAUSE); break; } break; } } } break; case WM_SIZING: { LPRECT pRect = (LPRECT)lParam; if (!bIsSingleWindow) { if (pRect->right - pRect->left < MAIN_WINDOW_MIN_WIDTH) pRect->right = pRect->left + MAIN_WINDOW_MIN_WIDTH; if (pRect->bottom - pRect->top != MAIN_WINDOW_HEIGHT) pRect->bottom = pRect->top + MAIN_WINDOW_HEIGHT; } return TRUE; } case WM_SIZE: { RECT Rect; if (hToolBar && hTrackBar) { SendMessage(hToolBar, TB_AUTOSIZE, 0, 0); SendMessage(hToolBar, TB_GETITEMRECT, 1, (LPARAM)&Rect); MoveWindow(hTimeDisplay, LOWORD(lParam) - 140, 4, 135, 18, TRUE); if (!bIsSingleWindow) { UINT Size = GetSystemMetrics(SM_CYMENU) + Rect.bottom; MoveWindow(hTrackBar, 0, 0, LOWORD(lParam), HIWORD(lParam) - Size, TRUE); } else { RECT ToolbarRect; MCI_DGV_PUT_PARMS mciPut; MoveWindow(hTrackBar, 180, 0, LOWORD(lParam) - 322, 25, TRUE); GetClientRect(hwnd, &Rect); GetClientRect(hToolBar, &ToolbarRect); mciPut.rc.top = 0; mciPut.rc.left = 0; mciPut.rc.right = Rect.right; mciPut.rc.bottom = Rect.bottom - (ToolbarRect.bottom - ToolbarRect.top) - 2; mciSendCommand(wDeviceId, MCI_PUT, MCI_DGV_PUT_DESTINATION | MCI_DGV_RECT | MCI_WAIT, (DWORD_PTR)&mciPut); } } return 0L; } case WM_HSCROLL: { if (hTrackBar == (HWND)lParam) { if (wDeviceId) { DWORD dwNewPos = (DWORD)SendMessage(hTrackBar, TBM_GETPOS, 0, 0); SeekPlayback(hwnd, dwNewPos); } else { SendMessage(hTrackBar, TBM_SETPOS, TRUE, 0); } } } break; case WM_NCLBUTTONDBLCLK: { if (wParam == HTCAPTION) { SwitchViewMode(hwnd); } } break; case WM_COMMAND: { if (LOWORD(wParam) >= IDM_DEVICE_FIRST) { HandleDeviceMenuItem(hwnd, LOWORD(wParam)); break; } switch (LOWORD(wParam)) { case IDC_PLAY: case IDC_PAUSE: { if (wDeviceId) TogglePlaybackState(hwnd); else OpenFileDialog(hwnd, 1, NULL); break; } case IDC_STOP: StopPlayback(hwnd); break; case IDC_EJECT: break; case IDC_BACKWARD: break; case IDC_SEEKBACK: SeekBackPlayback(hwnd); break; case IDC_SEEKFORW: SeekForwPlayback(hwnd); break; case IDC_FORWARD: break; case IDM_OPEN_FILE: OpenFileDialog(hwnd, 1, NULL); return 0; case IDM_CLOSE_FILE: CloseMediaFile(hwnd); break; case IDM_REPEAT: { if (!bRepeat) { CheckMenuItem(hMainMenu, IDM_REPEAT, MF_BYCOMMAND | MF_CHECKED); bRepeat = TRUE; } else { CheckMenuItem(hMainMenu, IDM_REPEAT, MF_BYCOMMAND | MF_UNCHECKED); bRepeat = FALSE; } break; } case IDM_SWITCHVIEW: SwitchViewMode(hwnd); break; case IDM_DEVPROPS: ShowDeviceProperties(hwnd); break; case IDM_VOLUMECTL: ShellExecute(hwnd, NULL, _T("SNDVOL32.EXE"), NULL, NULL, SW_SHOWNORMAL); break; case IDM_ABOUT: { HICON mplayIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN)); ShellAbout(hwnd, szAppTitle, 0, mplayIcon); DeleteObject(mplayIcon); break; } case IDM_EXIT: PostMessage(hwnd, WM_CLOSE, 0, 0); return 0; } break; } case WM_DESTROY: CloseMediaFile(hwnd); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, Message, wParam, lParam); } INT WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR lpCmdLine, INT nCmdShow) { WNDCLASSEX WndClass = {0}; TCHAR szClassName[] = _T("ROSMPLAY32"); HWND hwnd; MSG msg; DWORD dwError; HANDLE hAccel; hInstance = hInst; switch (GetUserDefaultUILanguage()) { case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT): SetProcessDefaultLayout(LAYOUT_RTL); break; default: break; } LoadString(hInstance, IDS_APPTITLE, szAppTitle, ARRAYSIZE(szAppTitle)); WndClass.cbSize = sizeof(WndClass); WndClass.lpszClassName = szClassName; WndClass.lpfnWndProc = MainWndProc; WndClass.hInstance = hInstance; WndClass.style = CS_HREDRAW | CS_VREDRAW; WndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN)); WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); WndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); WndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU); if (!RegisterClassEx(&WndClass)) { ShowLastWin32Error(NULL); return 0; } hwnd = CreateWindow(szClassName, szAppTitle, WS_SYSMENU | WS_MINIMIZEBOX | WS_THICKFRAME | WS_OVERLAPPED | WS_CAPTION | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, 350, MAIN_WINDOW_HEIGHT, NULL, NULL, hInstance, NULL); if (!hwnd) { ShowLastWin32Error(NULL); return 0; } hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(ID_ACCELERATORS)); BuildFileFilterAndDeviceMenu(); DragAcceptFiles(hwnd, TRUE); DisableMenuItems(); dwError = SearchPath(NULL, _T("SNDVOL32.EXE"), NULL, 0, NULL, NULL); if (dwError == 0) { EnableMenuItem(hMainMenu, IDM_VOLUMECTL, MF_BYCOMMAND | MF_GRAYED); } /* Show it */ ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); OpenMediaFile(hwnd, lpCmdLine, NULL); /* Message Loop */ while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(hwnd, hAccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } CleanupFileFilter(); DestroyAcceleratorTable(hAccel); return (INT)msg.wParam; }