Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

566 lines
17 KiB

  1. /*--------------------------------------------------------------------
  2. |
  3. | LangPlay.c - Sample Win app to play AVI movies using MCIWnd. Handles
  4. | multiple language track movies and lets the
  5. | user select the track to listen to at playback.
  6. |
  7. |
  8. +--------------------------------------------------------------------*/
  9. /**************************************************************************
  10. *
  11. * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  12. * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  13. * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  14. * PURPOSE.
  15. *
  16. * Copyright (c) 1992, 1993 Microsoft Corporation. All Rights Reserved.
  17. *
  18. **************************************************************************/
  19. #include <windows.h>
  20. #include <commdlg.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <direct.h>
  24. #include <mmsystem.h>
  25. #include <digitalv.h>
  26. #include "win32.h"
  27. #include <vfw.h>
  28. #include "langplay.h"
  29. /**************************************************************
  30. ************************ GLOBALS ******************************
  31. **************************************************************/
  32. /* AVI stuff to keep around */
  33. HWND hwndMovie; /* window handle of the movie */
  34. BOOL fMovieOpen = FALSE; /* Open flag: TRUE == movie open, FALSE = none */
  35. HMENU hMenuBar = NULL; /* menu bar handle */
  36. char szAppName [] = "LangPlay";
  37. // struct for handling multi-language support
  38. typedef struct langs_tag {
  39. WORD wLangTag; // language type tag
  40. char achName[64]; // stream name (limited to 64 chars by AVIStreamInfo)
  41. } LANGS, FAR *LPLANGS;
  42. #define NOAUDIO 0 // no audio stream
  43. int iCurLang; // current language selected (0 == NONE)
  44. /* function declarations */
  45. long FAR PASCAL _export WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  46. void fileOpenMovie(HWND hWnd);
  47. void menubarUpdate(HWND hWnd);
  48. void titlebarUpdate(HWND hWnd, LPSTR lpstrMovie);
  49. /* language specific functions */
  50. BOOL enumLangs(HWND hwnd, LPSTR lpstrMovie);
  51. void buildLangMenu(HWND hwnd, LPLANGS lpLangs, DWORD dwLangs);
  52. void switchLang(HWND hWnd, int iLangStream);
  53. /********************************************************************
  54. ************************** FUNCTIONS ********************************
  55. ********************************************************************/
  56. /*--------------------------------------------------------------+
  57. | initApp - initialize the app overall. |
  58. | |
  59. | Returns the Window handle for the app on success, NULL if |
  60. | there is a failure. |
  61. | |
  62. +--------------------------------------------------------------*/
  63. HWND initApp(HINSTANCE hInstance, HINSTANCE hPrevInstance, int nCmdShow)
  64. {
  65. HWND hWnd; /* window handle to return */
  66. int iWinHeight;
  67. WORD wVer;
  68. /* first let's make sure we are running on 1.1 */
  69. wVer = HIWORD(VideoForWindowsVersion());
  70. if (wVer < 0x010a){
  71. /* oops, we are too old, blow out of here */
  72. MessageBeep(MB_ICONHAND);
  73. MessageBox(NULL, "Video for Windows version is too old",
  74. "LangPlay Error", MB_OK|MB_ICONSTOP);
  75. return FALSE;
  76. }
  77. if (!hPrevInstance){
  78. WNDCLASS wndclass;
  79. wndclass.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
  80. wndclass.lpfnWndProc = WndProc;
  81. wndclass.cbClsExtra = 0;
  82. wndclass.cbWndExtra = 0;
  83. wndclass.hInstance = hInstance;
  84. wndclass.hIcon = LoadIcon (hInstance, "AppIcon");
  85. wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
  86. wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  87. wndclass.lpszMenuName = szAppName;
  88. wndclass.lpszClassName = szAppName;
  89. if (!RegisterClass(&wndclass)){
  90. MessageBox(NULL, "RegisterClass failure", szAppName, MB_OK);
  91. return NULL;
  92. }
  93. }
  94. iWinHeight = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYMENU) +
  95. (GetSystemMetrics(SM_CYFRAME) * 2);
  96. /* create the main window for the app */
  97. hWnd = CreateWindow(szAppName, szAppName, WS_OVERLAPPEDWINDOW |
  98. WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, 180, iWinHeight,
  99. NULL, NULL, hInstance, NULL);
  100. if (hWnd == NULL){
  101. MessageBox(NULL, "CreateWindow failure", szAppName, MB_OK);
  102. return NULL;
  103. }
  104. hMenuBar = GetMenu(hWnd); /* get the menu bar handle */
  105. menubarUpdate(hWnd); /* update menu bar to disable Movie menu */
  106. /* Show the main window */
  107. ShowWindow(hWnd, nCmdShow);
  108. UpdateWindow(hWnd);
  109. /* create the movie window using MCIWnd that has no file open initially */
  110. hwndMovie = MCIWndCreate(hWnd, hInstance, WS_CHILD |WS_VISIBLE | MCIWNDF_NOOPEN |
  111. MCIWNDF_NOERRORDLG | MCIWNDF_NOTIFYSIZE, NULL);
  112. if (!hwndMovie){
  113. /* we didn't get the movie window, destroy the app's window and bail out */
  114. DestroyWindow(hWnd);
  115. return NULL;
  116. }
  117. return hWnd;
  118. }
  119. /*--------------------------------------------------------------+
  120. | WinMain - main routine. |
  121. | |
  122. +--------------------------------------------------------------*/
  123. int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
  124. LPSTR lpszCmdParam, int nCmdShow)
  125. {
  126. HWND hWnd;
  127. MSG msg;
  128. if ((hWnd = initApp(hInstance, hPrevInstance,nCmdShow)) == NULL)
  129. return 0; /* died initializing, bail out */
  130. while (GetMessage(&msg, NULL, 0, 0)){
  131. TranslateMessage(&msg);
  132. DispatchMessage(&msg);
  133. }
  134. return msg.wParam;
  135. }
  136. /*--------------------------------------------------------------+
  137. | WndProc - window proc for the app |
  138. | |
  139. +--------------------------------------------------------------*/
  140. long FAR PASCAL _export WndProc (HWND hWnd, UINT message, WPARAM wParam,
  141. LPARAM lParam)
  142. {
  143. PAINTSTRUCT ps;
  144. WORD w;
  145. WORD wMenu;
  146. RECT rc;
  147. switch (message){
  148. case WM_CREATE:
  149. return 0;
  150. case WM_INITMENUPOPUP:
  151. /* be sure this isn't the system menu */
  152. if (HIWORD(lParam))
  153. return DefWindowProc(hWnd, WM_INITMENUPOPUP,
  154. wParam, lParam);
  155. wMenu = LOWORD(lParam);
  156. switch (wMenu){
  157. case 0: /* file menu */
  158. /* turn on/off CLOSE & PLAY */
  159. if (fMovieOpen) w = MF_ENABLED|MF_BYCOMMAND;
  160. else w = MF_GRAYED|MF_BYCOMMAND;
  161. EnableMenuItem((HMENU)wParam, IDM_CLOSE, w);
  162. break;
  163. } /* switch */
  164. break;
  165. case WM_COMMAND:
  166. if (wParam >= IDM_STREAM){
  167. // the command is to switch the audio stream
  168. switchLang(hWnd, wParam - IDM_STREAM + 1);
  169. return 0;
  170. }
  171. /* handle the menu commands */
  172. switch (wParam) {
  173. /* File Menu */
  174. case IDM_OPEN:
  175. fileOpenMovie(hWnd);
  176. break;
  177. case IDM_CLOSE:
  178. fMovieOpen = FALSE;
  179. MCIWndClose(hwndMovie); // close the movie
  180. ShowWindow(hwndMovie, SW_HIDE); //hide the window
  181. menubarUpdate(hWnd);
  182. titlebarUpdate(hWnd, NULL); // title bar back to plain
  183. break;
  184. case IDM_EXIT:
  185. PostMessage(hWnd, WM_CLOSE, 0, 0L);
  186. break;
  187. /* audio menu */
  188. case IDM_NONE:
  189. switchLang(hWnd, NOAUDIO);
  190. break;
  191. }
  192. return 0;
  193. case WM_PAINT:
  194. BeginPaint(hWnd, &ps);
  195. EndPaint(hWnd, &ps);
  196. return 0;
  197. case WM_SIZE:
  198. if (hwndMovie && fMovieOpen)
  199. MoveWindow(hwndMovie,0,0,LOWORD(lParam),HIWORD(lParam),TRUE);
  200. break;
  201. case WM_DESTROY:
  202. if (fMovieOpen)
  203. MCIWndClose(hwndMovie); // close an open movie
  204. MCIWndDestroy(hwndMovie); // now destroy the MCIWnd window
  205. PostQuitMessage(0);
  206. return 0;
  207. case MCIWNDM_NOTIFYSIZE:
  208. if (fMovieOpen){
  209. /* adjust to size of the movie window */
  210. GetWindowRect(hwndMovie, &rc);
  211. AdjustWindowRect(&rc, GetWindowLong(hWnd, GWL_STYLE), TRUE);
  212. #ifndef WIN32
  213. rc.bottom++; // AdjustWindowRect is broken
  214. #endif
  215. SetWindowPos(hWnd, NULL, 0, 0, rc.right - rc.left,
  216. rc.bottom - rc.top,
  217. SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
  218. } else {
  219. /* movie closed, adjust to the default size */
  220. int iWinHeight;
  221. iWinHeight = GetSystemMetrics(SM_CYCAPTION) +
  222. GetSystemMetrics(SM_CYMENU) +
  223. (GetSystemMetrics(SM_CYFRAME) * 2);
  224. SetWindowPos(hWnd, NULL, 0, 0, 180, iWinHeight,
  225. SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
  226. }
  227. break;
  228. case WM_ACTIVATE:
  229. case WM_QUERYNEWPALETTE:
  230. case WM_PALETTECHANGED:
  231. //
  232. // Forward palette-related messages through to the MCIWnd,
  233. // so it can do the right thing.
  234. //
  235. if (hwndMovie)
  236. return SendMessage(hwndMovie, message, wParam, lParam);
  237. break;
  238. } /* switch */
  239. return DefWindowProc(hWnd, message, wParam, lParam);
  240. }
  241. /*--------------------------------------------------------------+
  242. | menubarUpdate - update the menu bar based on the <fMovieOpen> |
  243. | flag value. This will turn on/off the |
  244. | Movie menu. |
  245. | |
  246. +--------------------------------------------------------------*/
  247. void menubarUpdate(HWND hWnd)
  248. {
  249. WORD w;
  250. if (fMovieOpen){
  251. w = MF_ENABLED|MF_BYPOSITION;
  252. } else {
  253. w = MF_GRAYED|MF_BYPOSITION;
  254. }
  255. EnableMenuItem(hMenuBar, 1, w); /* change the Movie menu (#1) */
  256. DrawMenuBar(hWnd); /* re-draw the menu bar */
  257. }
  258. /*--------------------------------------------------------------+
  259. | titlebarUpdate - update the title bar to include the name |
  260. | of the movie playing. |
  261. | |
  262. +--------------------------------------------------------------*/
  263. void titlebarUpdate(HWND hWnd, LPSTR lpstrMovie)
  264. {
  265. char achNewTitle[BUFFER_LENGTH]; // space for the title
  266. if (lpstrMovie != NULL)
  267. wsprintf((LPSTR)achNewTitle,"%s - %s", (LPSTR)szAppName,lpstrMovie);
  268. else
  269. lstrcpy((LPSTR)achNewTitle, (LPSTR)szAppName);
  270. SetWindowText(hWnd, (LPSTR)achNewTitle);
  271. }
  272. /*--------------------------------------------------------------+
  273. | fileOpenMovie - open an AVI movie. Use CommDlg open box to |
  274. | open and then handle the initialization to |
  275. | show the movie and position it properly. Keep |
  276. | the movie paused when opened. |
  277. | |
  278. | Sets <fMovieOpened> on success. |
  279. +--------------------------------------------------------------*/
  280. void fileOpenMovie(HWND hWnd)
  281. {
  282. OPENFILENAME ofn;
  283. static char szFile [BUFFER_LENGTH];
  284. static char szFileTitle [BUFFER_LENGTH];
  285. /* use the OpenFile dialog to get the filename */
  286. memset(&ofn, 0, sizeof(ofn));
  287. ofn.lStructSize = sizeof(ofn);
  288. ofn.hwndOwner = hWnd;
  289. ofn.lpstrFilter = "Video for Windows\0*.avi\0\0";
  290. ofn.lpstrFile = szFile;
  291. ofn.nMaxFile = sizeof(szFile);
  292. ofn.lpstrFileTitle = szFileTitle;
  293. ofn.nMaxFileTitle = sizeof(szFileTitle);
  294. ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
  295. /* use MCIWnd to get our filename */
  296. if (GetOpenFileNamePreview(&ofn)){
  297. /* we got a filename, now close any old movie and open */
  298. /* the new one. */
  299. if (fMovieOpen)
  300. MCIWndClose(hwndMovie);
  301. enumLangs(hWnd, ofn.lpstrFile); // find out the languages used in the file.
  302. /* try to open the file */
  303. fMovieOpen = TRUE; // assume the best
  304. if (MCIWndOpen(hwndMovie, ofn.lpstrFile, 0) == 0){
  305. /* we opened the file o.k., now set up to */
  306. /* play it. */
  307. ShowWindow(hwndMovie, SW_SHOW);
  308. } else {
  309. /* generic error for open */
  310. MessageBox(hWnd, "Unable to open Movie", NULL,
  311. MB_ICONEXCLAMATION|MB_OK);
  312. fMovieOpen = FALSE;
  313. }
  314. }
  315. /* update menu bar */
  316. menubarUpdate(hWnd);
  317. if (fMovieOpen)
  318. titlebarUpdate(hWnd, (LPSTR)ofn.lpstrFileTitle);
  319. else
  320. titlebarUpdate(hWnd, NULL);
  321. /* cause an update to occur */
  322. InvalidateRect(hWnd, NULL, FALSE);
  323. UpdateWindow(hWnd);
  324. }
  325. /*--------------------------------------------------------------+
  326. | enumLangs - enumerate the audio streams in a file and set up |
  327. | the global ghLangs as a handle to the array of |
  328. | language streams. | |
  329. | |
  330. | To do this: |
  331. | 1. Open the file using AVIFileOpen(). |
  332. | 2. Open all Audio Streams, getting the pavi for it |
  333. | 3. Get the stream info on all audio streams to get names|
  334. | 4. If names don't exist use "Audio Strean n" |
  335. | 5. Close the file |
  336. | 6. Build the audio stream menu |
  337. | |
  338. | Return TRUE if successfully set up menu, FALSE on any error |
  339. | |
  340. +--------------------------------------------------------------*/
  341. BOOL enumLangs(HWND hWnd, LPSTR lpstrMovie)
  342. {
  343. PAVIFILE pFile;
  344. PAVISTREAM pStream;
  345. AVIFILEINFO aviInfo;
  346. AVISTREAMINFO aviStream;
  347. DWORD dwNumStreams;
  348. DWORD dwNumAudioStreams = 0L;
  349. LPLANGS lpLangs;
  350. LPLANGS lpLang;
  351. HANDLE hLangs;
  352. DWORD dw;
  353. AVIFileInit();
  354. // go open the file
  355. if (AVIFileOpen((PAVIFILE far *)&pFile, lpstrMovie, OF_READ, NULL) != 0)
  356. return FALSE;
  357. // get the file information
  358. AVIFileInfo(pFile, (LPAVIFILEINFO)&aviInfo, sizeof(aviInfo));
  359. dwNumStreams = aviInfo.dwStreams; // grab the number of streams
  360. // loop through the streams and find the # of audio streams
  361. for (dw = 0L; dw < dwNumStreams; dw++){
  362. AVIFileGetStream(pFile, (PAVISTREAM far *)&pStream, 0, dw);
  363. AVIStreamInfo(pStream, (LPAVISTREAMINFO)&aviStream, sizeof(aviStream));
  364. if (aviStream.fccType == streamtypeAUDIO)
  365. dwNumAudioStreams++;
  366. AVIStreamClose(pStream);
  367. }
  368. // we now know how many audio streams we are dealing with, we need to allocate
  369. // enough memory for the Langs array and then get all the audio stream information
  370. // again.
  371. hLangs = GlobalAlloc(GHND, (sizeof(LANGS) * dwNumAudioStreams));
  372. if (hLangs == NULL)
  373. return FALSE;
  374. lpLangs = GlobalLock(hLangs); // get the memory
  375. // loop through the audio streams and fill out the array
  376. for (dw = 0L, lpLang = lpLangs; dw < dwNumAudioStreams; dw++, lpLang++) {
  377. AVIFileGetStream(pFile, (PAVISTREAM far *)&pStream, streamtypeAUDIO, dw);
  378. AVIStreamInfo(pStream, (LPAVISTREAMINFO)&aviStream, sizeof(aviStream));
  379. if (aviStream.szName && *aviStream.szName != '\0')
  380. lstrcpy((LPSTR)lpLang->achName, (LPSTR)aviStream.szName);
  381. else
  382. wsprintf((LPSTR)lpLang->achName, "Audio Stream %lu",dw);
  383. AVIStreamClose(pStream);
  384. }
  385. // now build the menu for this
  386. buildLangMenu(hWnd, lpLangs, dwNumAudioStreams);
  387. // close up and deallocate resources
  388. AVIFileClose(pFile);
  389. AVIFileExit();
  390. GlobalUnlock(hLangs);
  391. GlobalFree(hLangs);
  392. return TRUE;
  393. }
  394. /*--------------------------------------------------------------+
  395. | buildLangMenu - build up the language menu for the audio |
  396. | streams available. |
  397. | |
  398. | hwnd is the main application window handle |
  399. | lang points to an array of LANGSTRUCT entries already filled |
  400. | in by the caller. |
  401. +--------------------------------------------------------------*/
  402. void buildLangMenu(HWND hwnd, LPLANGS lpLangs, DWORD dwLangs)
  403. {
  404. UINT i;
  405. HMENU hMenu;
  406. LPLANGS lplang;
  407. UINT uNumMenus;
  408. // go through menu chain and get the Audio Stream pop-up menu
  409. hMenu = GetMenu(hwnd); // get the menu bar
  410. hMenu = GetSubMenu(hMenu, 1); // get the Audio Stream menu
  411. uNumMenus = GetMenuItemCount(hMenu); // how many items are on this menu?
  412. if (uNumMenus > 1){
  413. // we've got a menu with items already, time to delete all of them
  414. // except for the first one (NONE). NOTE: Item 0 == first item
  415. // be sure to delete in reverse order so you get them all.
  416. for ( --uNumMenus; uNumMenus; uNumMenus--) {
  417. DeleteMenu(hMenu, uNumMenus, MF_BYPOSITION);
  418. }
  419. }
  420. // loop through the languages and add menus to the existing menu
  421. for (i=0, lplang = lpLangs; i<dwLangs; i++, lplang++){
  422. AppendMenu(hMenu, MF_ENABLED | MF_STRING, IDM_STREAM+i, lplang->achName);
  423. }
  424. // get default set up
  425. if (dwLangs)
  426. iCurLang = 1; // use first audio stream
  427. else
  428. iCurLang = NOAUDIO; // else none
  429. /* set up the checkmark initially */
  430. CheckMenuItem(hMenu, (iCurLang), MF_BYPOSITION | MF_CHECKED);
  431. }
  432. /*------------------------------------------------------------------+
  433. | switchLang - switch audio stream playback |
  434. | |
  435. | iLangStream == the audio stream to switch to (-1 == NONE) |
  436. | Be sure to update iCurrLang global to be the current audio stream |
  437. | selected. |
  438. | |
  439. +------------------------------------------------------------------*/
  440. void switchLang(HWND hWnd, int iLangStream)
  441. {
  442. HMENU hMenu;
  443. char achStrBuff[256];
  444. // if user just picked the same stream then just get out of here
  445. if (iCurLang == iLangStream)
  446. return;
  447. // go through menu chain and get the Audio Stream pop-up menu
  448. hMenu = GetMenu(hWnd); // get the menu bar
  449. hMenu = GetSubMenu(hMenu, 1); // get the Audio Stream menu
  450. // turn off the checkmark from the old item
  451. CheckMenuItem(hMenu, (iCurLang), MF_BYPOSITION | MF_UNCHECKED);
  452. // turn on the checkmark on the new item
  453. CheckMenuItem(hMenu, (iLangStream), MF_BYPOSITION | MF_CHECKED);
  454. if (iLangStream == NOAUDIO){
  455. // turn off all audio
  456. MCIWndSendString(hwndMovie, "setaudio off");
  457. } else {
  458. // turn on audio & the specific stream
  459. wsprintf(achStrBuff, "setaudio stream to %d", iLangStream);
  460. // send the command
  461. MCIWndSendString(hwndMovie, achStrBuff);
  462. if (iCurLang == NOAUDIO){
  463. // audio was off, turn it on
  464. MCIWndSendString(hwndMovie, "setaudio on");
  465. }
  466. }
  467. iCurLang = iLangStream; // set the current stream
  468. }
  469. /*--------------------------- end of file ----------------------*/