mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
016acd170d
CORE-18369
1562 lines
43 KiB
C
1562 lines
43 KiB
C
/*
|
|
* 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
|
|
|
|
#ifdef UNICODE
|
|
#define argv __wargv
|
|
#else
|
|
#define argv __argv
|
|
#endif
|
|
|
|
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;
|
|
size_t uSizeRemain;
|
|
size_t 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("");
|
|
|
|
ZeroMemory(&OpenFileName, sizeof(OpenFileName));
|
|
|
|
OpenFileName.lStructSize = sizeof(OpenFileName);
|
|
OpenFileName.hwndOwner = hwnd;
|
|
OpenFileName.hInstance = hInstance;
|
|
OpenFileName.lpstrFilter = szFilter;
|
|
OpenFileName.lpstrFile = szFile;
|
|
OpenFileName.nMaxFile = ARRAYSIZE(szFile);
|
|
OpenFileName.Flags = OFN_EXPLORER | 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:
|
|
{
|
|
ShellAbout(hwnd, szAppTitle, NULL,
|
|
LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN)));
|
|
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);
|
|
|
|
if (*lpCmdLine == _T('"'))
|
|
{
|
|
OpenMediaFile(hwnd, argv[1], NULL);
|
|
}
|
|
else
|
|
{
|
|
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;
|
|
}
|