LANGPLAY.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:24k
源码类别:

Windows编程

开发平台:

Visual C++

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