PageRenderTime 53ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/reactos/base/applications/mplay32/mplay32.c

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