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

Windows编程

开发平台:

Visual C++

  1. /**************************************************************************
  2.  *
  3.  *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4.  *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5.  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6.  *  PURPOSE.
  7.  *
  8.  *  Copyright (C) 1992 - 1997 Microsoft Corporation.  All Rights Reserved.
  9.  *
  10.  **************************************************************************/
  11. /****************************************************************************
  12.  *
  13.  *   vidcap.c: WinMain and command processing
  14.  *
  15.  *   Vidcap32 Source code
  16.  *
  17.  ***************************************************************************/
  18.  
  19. #include <windows.h>
  20. #include <windowsx.h>
  21. #include <commdlg.h>
  22. #include <mmsystem.h>
  23. #include <mmreg.h>
  24. #include <io.h>
  25. #include <fcntl.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <memory.h>
  29. #include <dos.h>
  30. #include <shellapi.h>
  31. #include <vfw.h>
  32. #include "vidcap.h"
  33. #include "vidframe.h"
  34. #include "profile.h"
  35. // generic window control classes
  36. #include "toolbar.h"
  37. #include "status.h"
  38. #include "arrow.h"
  39. #include "rlmeter.h"
  40. #include "help.h"
  41. // the standard toolbar class 'exports' this but doesn't put it in the
  42. // header file
  43. extern char     szToolBarClass[];//HACK!
  44. // height of the buttons on a toolbar - depends on the
  45. // size of the bitmaps within IDBMP_TOOLBAR
  46. #define BUTTONWIDTH     24
  47. #define BUTTONHEIGHT    22
  48. #define TOOLBAR_HEIGHT          BUTTONHEIGHT + 6
  49. // description and layout of toolbar buttons within IDBMP_TOOLBAR
  50. #define APP_NUMTOOLS 8
  51. #define BTN_SETFILE 0
  52. #define BTN_EDITCAP 1
  53. #define BTN_LIVE 2
  54. #define BTN_CAPFRAME 3
  55. #define BTN_CAPSEL 4
  56. #define BTN_CAPAVI 5
  57. #define BTN_CAPPAL 6
  58. #define BTN_OVERLAY 7
  59. static int           aiButton[] = {BTN_SETFILE, BTN_EDITCAP,
  60.                             BTN_LIVE, BTN_OVERLAY, BTN_CAPFRAME,
  61.                             BTN_CAPSEL, BTN_CAPAVI, BTN_CAPPAL };
  62. static int           aiState[] = {BTNST_FOCUSUP, BTNST_UP,
  63.                             BTNST_UP, BTNST_UP, BTNST_UP,
  64.                             BTNST_UP, BTNST_UP, BTNST_UP};
  65. static int           aiType[] ={BTNTYPE_PUSH, BTNTYPE_PUSH,
  66.                             BTNTYPE_CHECKBOX, BTNTYPE_CHECKBOX,
  67.                             BTNTYPE_PUSH,
  68.                             BTNTYPE_PUSH, BTNTYPE_PUSH, BTNTYPE_PUSH};
  69. static int           aiString[] = { IDC_toolbarSETFILE,
  70.                             IDC_toolbarEDITCAP, IDC_toolbarLIVE,
  71.                             IDC_toolbarOVERLAY,
  72.                             IDC_toolbarCAPFRAME, IDC_toolbarCAPSEL,
  73.                             IDC_toolbarCAPAVI, IDC_toolbarCAPPAL };
  74. static int           aPos[] = { 10, 35, 75, 100, 150, 175, 200, 225 };
  75. //
  76. // Global Variables
  77. //
  78. // preferences
  79. BOOL gbCentre;
  80. BOOL gbToolBar;
  81. BOOL gbStatusBar;
  82. BOOL gbAutoSizeFrame;
  83. int gBackColour;
  84. BOOL gbLive, gbOverlay;
  85. BOOL gfIsRTL;
  86. // saved window sizes
  87. int gWinX, gWinY;
  88. int gWinCX, gWinCY;
  89. int gWinShow;
  90. // command line options
  91. int gCmdLineDeviceID = -1;
  92. char           gachAppName[]  = "vidcapApp" ;
  93. char           gachIconName[] = "vidcapIcon" ;
  94. char           gachMenuName[] = "vidcapMenu" ;
  95. char           gachAppTitle[20];    //VidCap
  96. char           gachCaptureFile[_MAX_PATH];
  97. char           gachMCIDeviceName[21];
  98. char           gachString[128] ;
  99. char           gachBuffer[200] ;
  100. char           gachLastError[256];
  101. HINSTANCE      ghInstApp ;
  102. HWND           ghWndMain = NULL ;
  103. HWND           ghWndFrame;      // child of ghWndMain  - frames and scrolls
  104. HWND           ghWndCap  ;      // child of ghWndCap
  105. HWND           ghWndToolBar;
  106. HWND           ghWndStatus;
  107. HANDLE         ghAccel ;
  108. WORD           gwDeviceIndex ;
  109. WORD           gwPalFrames = DEF_PALNUMFRAMES ;
  110. WORD           gwPalColors = DEF_PALNUMCOLORS ;
  111. WORD           gwCapFileSize ;
  112. CAPSTATUS      gCapStatus ;
  113. CAPDRIVERCAPS  gCapDriverCaps ;
  114. CAPTUREPARMS   gCapParms ;
  115. BOOL           gbHaveHardware;
  116. UINT           gDriverCount;
  117. BOOL           gbIsScrncap;  // For Scrncap.drv, we must yield
  118. BOOL           gbInLayout;
  119. UINT           gAVStreamMaster;
  120. HANDLE         ghwfex ;
  121. LPWAVEFORMATEX glpwfex ;
  122. FARPROC        fpErrorCallback ;
  123. FARPROC        fpStatusCallback ;
  124. FARPROC        fpYieldCallback ;
  125. // set to false when we capture a palette (or if we have warned him and
  126. // he says its ok
  127. BOOL bDefaultPalette = TRUE;
  128. #ifdef DEBUG
  129. int nTestCount;
  130. #endif
  131. // c-runtime cmd line
  132. extern char ** __argv;
  133. extern int __argc;
  134. #define LimitRange(Val,Low,Hi) (max(Low,(min(Val,Hi))))
  135. //
  136. // Function prototypes
  137. //
  138. LONG FAR PASCAL MainWndProc(HWND, UINT, UINT, LONG) ;
  139. LRESULT FAR PASCAL ErrorCallbackProc(HWND, int, LPSTR) ;
  140. LRESULT FAR PASCAL StatusCallbackProc(HWND, int, LPSTR) ;
  141. LRESULT FAR PASCAL YieldCallbackProc(HWND) ;
  142. void vidcapSetLive(BOOL bLive);
  143. void vidcapSetOverlay(BOOL bOverlay);
  144. void vidcapSetCaptureFile(LPSTR pFileName);
  145. BOOL vidcapRegisterClasses(HINSTANCE hInstance, HINSTANCE hPrevInstance);
  146. BOOL vidcapCreateWindows(HINSTANCE hInstance, HINSTANCE hPrevInstance);
  147. void vidcapLayout(HWND hwnd);
  148. BOOL vidcapEnumerateDrivers(HWND hwnd);
  149. BOOL vidcapInitHardware(HWND hwnd, HWND hwndCap, UINT uIndex);
  150. void vidcapReadProfile(void);
  151. void vidcapWriteProfile(void);
  152. void vidcapReadSettingsProfile(void);
  153. void vidcapWriteSettingsProfile(void);
  154. /* --- initialisation -------------------------------------------------- */
  155. //
  156. // WinMain: Application Entry Point Function
  157. //
  158. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
  159. {
  160. ///////////////////////////////////////////////////////////////////////
  161. //  hInstance:      handle for this instance
  162. //  hPrevInstance:  handle for possible previous instances
  163. //  lpszCmdLine:    long pointer to exec command line
  164. //  nCmdShow:       Show code for main window display
  165. ///////////////////////////////////////////////////////////////////////
  166.     MSG          msg ;
  167.     BOOL bValidCmdline;
  168.     BOOL fOK;
  169.     int i;
  170.     char ach[2];
  171.     ghInstApp = hInstance ;
  172.     LoadString(hInstance, IDS_CAP_RTL, ach, sizeof(ach));
  173.     gfIsRTL = ach[0] == '1';
  174.     gCmdLineDeviceID = -1;
  175.     // read the app title string - used in several message boxes
  176.     LoadString(hInstance, IDS_APP_TITLE, gachAppTitle, sizeof(gachAppTitle));
  177.     // read defaults out of the registry
  178.     vidcapReadProfile();
  179.     // look for cmd line options
  180.     bValidCmdline = TRUE;
  181.     for ( i = 1; (i < __argc) && bValidCmdline; i++) {
  182.         if ((__argv[i][0] == '/') || (__argv[i][0] == '-')) {
  183.             switch(__argv[i][1]) {
  184.             case 'D':
  185.             case 'd':
  186.                 if (gCmdLineDeviceID < 0) {
  187.                     // allow "-d0" and "-d 0"
  188.                     PSTR p = &__argv[i][2];
  189.                     if ((*p == 0) && ((i+1) < __argc)) {
  190.                         p = __argv[++i];
  191.                     }
  192.                     gCmdLineDeviceID = atoi(p);
  193.                 } else {
  194.                     bValidCmdline = FALSE;
  195.                 }
  196.                 break;
  197.             default:
  198.                 bValidCmdline = FALSE;
  199.             }
  200.         } else {
  201.             bValidCmdline = FALSE;
  202.         }
  203.     }
  204.     
  205.     if (gCmdLineDeviceID == -1)
  206. gCmdLineDeviceID = 0;
  207.     if (!bValidCmdline) {
  208.         MessageBoxID(IDS_ERR_CMDLINE, MB_OK|MB_ICONEXCLAMATION);
  209.         return(0);
  210.     }
  211.     if (!vidcapRegisterClasses(hInstance, hPrevInstance)) {
  212.         MessageBoxID(IDS_ERR_REGISTER_CLASS,
  213.         MB_ICONEXCLAMATION) ;
  214.         return 0 ;
  215.     }
  216.     if (!vidcapCreateWindows(hInstance, hPrevInstance)) {
  217.         MessageBoxID(IDS_ERR_CREATE_WINDOW,
  218.         MB_ICONEXCLAMATION | MB_OK) ;
  219.         return IDS_ERR_CREATE_WINDOW ;
  220.     }
  221.     // Get the default setup for video capture from the AVICap window
  222.     capCaptureGetSetup(ghWndCap, &gCapParms, sizeof(CAPTUREPARMS)) ;
  223.     // Overwrite the defaults with settings we have saved in the profile
  224.     vidcapReadSettingsProfile();
  225.     // Show the main window before connecting the hardware as this can be
  226.     // time consuming and the user should see something happening first...
  227.     ShowWindow(ghWndMain, nCmdShow) ;
  228.     UpdateWindow(ghWndMain) ;
  229.     ghAccel = LoadAccelerators(hInstance, "VIDCAP") ;
  230.     // Create a list of all capture drivers and append them to the Options menu
  231.     if (!(fOK = vidcapEnumerateDrivers(ghWndMain))) {
  232. LoadString(ghInstApp, IDS_ERR_FIND_HARDWARE, gachLastError, sizeof(gachLastError));
  233.     }
  234.     // Try to connect to a capture driver
  235.     else if (fOK = vidcapInitHardware(ghWndMain, ghWndCap, 
  236.        bValidCmdline ? gCmdLineDeviceID : 0)) {
  237. // Hooray, we now have a capture driver connected!
  238.         vidcapSetCaptureFile(gachCaptureFile);
  239.     }
  240.     
  241.     if (!fOK) {
  242.         if (!DoDialog(ghWndMain, IDD_NoCapHardware, NoHardwareDlgProc,
  243.                         (LONG) (LPSTR) gachLastError)) {
  244.             // The user has asked to abort, since no driver was available
  245.             PostMessage(ghWndMain, WM_COMMAND,
  246.                         GET_WM_COMMAND_MPS(IDM_F_EXIT, 0, 0));
  247.         }
  248.     }
  249.     
  250.     // All set; get and process messages
  251.     while (GetMessage(&msg, NULL, 0, 0)) {
  252.         if (! TranslateAccelerator(ghWndMain, ghAccel, &msg)) {
  253.             TranslateMessage(&msg) ;
  254.             DispatchMessage(&msg) ;
  255.         }
  256.     }
  257.     return msg.wParam;
  258. }  // End of WinMain
  259. BOOL
  260. vidcapRegisterClasses(HINSTANCE hInstance, HINSTANCE hPrevInstance)
  261. {
  262.     WNDCLASS wc;
  263.     if (! hPrevInstance) {
  264.         // If it's the first instance, register the window class
  265.         wc.lpszClassName = gachAppName ;
  266.         wc.hInstance     = hInstance ;
  267.         wc.lpfnWndProc   = MainWndProc ;
  268.         wc.hCursor       = LoadCursor(NULL, IDC_ARROW) ;
  269.         wc.hIcon         = LoadIcon(hInstance, gachIconName) ;
  270.         wc.lpszMenuName  = gachMenuName ;
  271.         wc.hbrBackground = GetStockObject(WHITE_BRUSH) ;
  272.         wc.style         = CS_HREDRAW | CS_VREDRAW ;
  273.         wc.cbClsExtra    = 0 ;
  274.         wc.cbWndExtra    = 0 ;
  275.         if (!RegisterClass(&wc)) {
  276.             return(FALSE);
  277.         }
  278.         if (!ArrowInit(hInstance)) {
  279.             return(FALSE);
  280.         }
  281.         if (!RLMeter_Register(hInstance)) {
  282.             return(FALSE);
  283.         }
  284.     }
  285.     if (!toolbarInit(hInstance, hPrevInstance)) {
  286.         return(FALSE);
  287.     }
  288.     if (!statusInit(hInstance, hPrevInstance)) {
  289.         return(FALSE);
  290.     }
  291.     return(TRUE);
  292. }
  293. BOOL
  294. vidcapCreateWindows(HINSTANCE hInstance, HINSTANCE hPrevInstance)
  295. {
  296.     POINT pt;
  297.     RECT rc;
  298.     TOOLBUTTON tb;
  299.     int i;
  300.     // Create Application's Main window
  301.     ghWndMain = CreateWindowEx(
  302.             gfIsRTL ? WS_EX_LEFTSCROLLBAR | WS_EX_RIGHT | WS_EX_RTLREADING : 0,
  303.             gachAppName,
  304.             gachAppTitle,
  305.             WS_CAPTION      |
  306.             WS_SYSMENU      |
  307.             WS_MINIMIZEBOX  |
  308.             WS_MAXIMIZEBOX  |
  309.             WS_THICKFRAME   |
  310.             WS_CLIPCHILDREN |
  311.             WS_OVERLAPPED,
  312.             gWinX, gWinY,
  313.             gWinCX, gWinCY,
  314.             NULL,
  315.             NULL,
  316.             hInstance,
  317.             0) ;
  318.     if (ghWndMain == NULL) {
  319.         return(FALSE);
  320.     }
  321.     /*
  322.      * create a vidframe child window - this will create a child
  323.      * AVICAP window within itself.
  324.      *
  325.      * Don't worry about size and position - vidcapLayout will do this
  326.      * later (once we know the video format size).
  327.      */
  328.     ghWndFrame = vidframeCreate(
  329.                     ghWndMain,
  330.                     hInstance,
  331.                     hPrevInstance,
  332.                     0, 0, 0, 0,
  333.                     &ghWndCap);
  334.     if ((ghWndFrame == NULL) || (ghWndCap == NULL)) {
  335.         return(FALSE);
  336.     }
  337.     // Register the status and error callbacks before driver connects
  338.     // so we can get feedback about the connection process
  339.     fpErrorCallback = MakeProcInstance((FARPROC)ErrorCallbackProc, ghInstApp) ;
  340.     capSetCallbackOnError(ghWndCap, fpErrorCallback) ;
  341.     fpStatusCallback = MakeProcInstance((FARPROC)StatusCallbackProc, ghInstApp) ;
  342.     capSetCallbackOnStatus(ghWndCap, fpStatusCallback) ;
  343.     // We'll only install a yield callback later if using Scrncap.drv
  344.     fpYieldCallback = MakeProcInstance((FARPROC)YieldCallbackProc, ghInstApp) ;
  345.     
  346.     /*
  347.      * CREATE THE TOOL BAR WINDOW
  348.      */
  349.     /* NOTE: let vidcapLayout() position it */
  350.     ghWndToolBar = CreateWindowEx(
  351.             gfIsRTL ? WS_EX_LEFTSCROLLBAR | WS_EX_RIGHT | WS_EX_RTLREADING : 0,
  352.             szToolBarClass,
  353.             NULL,
  354.             WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP|
  355.             WS_CLIPSIBLINGS,
  356.             0, 0,
  357.             0, 0,
  358.             ghWndMain,
  359.             NULL,
  360.             hInstance,
  361.             NULL);
  362.     if (ghWndToolBar == NULL) {
  363.         return(FALSE);
  364.     }
  365.     /* set the bitmap and button size to be used for this toolbar */
  366.     pt.x = BUTTONWIDTH;
  367.     pt.y = BUTTONHEIGHT;
  368.     toolbarSetBitmap(ghWndToolBar, hInstance, IDBMP_TOOLBAR, pt);
  369.     for (i = 0; i < APP_NUMTOOLS; i++) {
  370. rc.left = aPos[i];
  371. rc.top = 2;
  372. rc.right = rc.left + pt.x;
  373. rc.bottom = rc.top + pt.y;
  374. tb.rc = rc;
  375. tb.iButton = aiButton[i];
  376. tb.iState = aiState[i];
  377. tb.iType = aiType[i];
  378. tb.iString = aiString[i];
  379. toolbarAddTool(ghWndToolBar, tb);
  380.     }
  381.     // create the status bar - let vidcapLayout do the positioning
  382.     ghWndStatus = CreateWindowEx(
  383.                     gfIsRTL ? WS_EX_LEFTSCROLLBAR | WS_EX_RIGHT | WS_EX_RTLREADING : 0,
  384.                     szStatusClass,
  385.                     NULL,
  386.                     WS_CHILD|WS_BORDER|WS_VISIBLE|WS_CLIPSIBLINGS,
  387.                     0, 0,
  388.                     0, 0,
  389.                     ghWndMain,
  390.                     NULL,
  391.                     hInstance,
  392.                     NULL);
  393.     if (ghWndStatus == NULL) {
  394.         return(FALSE);
  395.     }
  396.     return(TRUE);
  397. }
  398. /*
  399.  * Enumerate the potential capture drivers and add the list to the Options
  400.  * menu.  This function is only called once at startup.
  401.  * Returns FALSE if no drivers are available.
  402.  */
  403. BOOL
  404. vidcapEnumerateDrivers(HWND hwnd)
  405. {
  406.     char    achDeviceVersion[80] ;
  407.     char    achDeviceAndVersion[160] ;
  408.     UINT    uIndex ;
  409.     HMENU   hMenuSub;
  410.     gDriverCount = 0 ;
  411.     hMenuSub = GetSubMenu (GetMenu (hwnd), 2);  // Options menu
  412.     for (uIndex = 0 ; uIndex < MAXVIDDRIVERS ; uIndex++) {
  413.         if (capGetDriverDescription(uIndex,
  414.                        (LPSTR)achDeviceAndVersion, sizeof(achDeviceAndVersion),
  415.                        (LPSTR)achDeviceVersion, sizeof(achDeviceVersion))) {
  416.             // Concatenate the device name and version strings
  417.             lstrcat (achDeviceAndVersion, ",   ");
  418.             lstrcat (achDeviceAndVersion, achDeviceVersion);
  419.             AppendMenu (hMenuSub, 
  420.                         MF_STRING,
  421.                         IDM_O_DRIVER0 + uIndex, 
  422.                         achDeviceAndVersion);
  423.             gDriverCount++;
  424.         }
  425.         else
  426.             break;
  427.     }  
  428.     // Now refresh menu, position capture window, start driver etc
  429.     DrawMenuBar(ghWndMain) ;
  430.     return (gDriverCount);
  431. }
  432. /*
  433.  * Connect the capture window to a capture driver.
  434.  * uIndex specifies the index of the driver to use.
  435.  * Returns TRUE on success, or FALSE if the driver connection failed.
  436.  */
  437. BOOL
  438. vidcapInitHardware(HWND hwnd, HWND hwndCap, UINT uIndex)
  439. {
  440.     UINT    uError ;
  441.     UINT    uI;
  442.     HMENU   hMenu;
  443.     char    szName[MAX_PATH];
  444.     char    szVersion[MAX_PATH];
  445.     // Since the driver may not provide a reliable error string
  446.     // provide a default
  447.     LoadString(ghInstApp, IDS_ERR_FIND_HARDWARE, gachLastError, sizeof(gachLastError));
  448.     // Try connecting to the capture driver
  449.     if (uError = capDriverConnect(hwndCap, uIndex)) {
  450.         gbHaveHardware = TRUE;
  451.         gwDeviceIndex = uIndex;
  452.     }
  453.     else {
  454.         gbHaveHardware = FALSE;
  455.         gbLive = FALSE;
  456.         gbOverlay = FALSE;
  457.     }
  458.     // Get the capabilities of the capture driver
  459.     capDriverGetCaps(hwndCap, &gCapDriverCaps, sizeof(CAPDRIVERCAPS)) ;
  460.     // Get the settings for the capture window
  461.     capGetStatus(hwndCap, &gCapStatus , sizeof(gCapStatus));
  462.     // Modify the toolbar buttons
  463.     toolbarModifyState(ghWndToolBar, BTN_CAPFRAME, 
  464.         gbHaveHardware ? BTNST_UP : BTNST_GRAYED);
  465.     toolbarModifyState(ghWndToolBar, BTN_CAPSEL, 
  466.         gbHaveHardware ? BTNST_UP : BTNST_GRAYED);
  467.     toolbarModifyState(ghWndToolBar, BTN_CAPAVI, 
  468.         gbHaveHardware ? BTNST_UP : BTNST_GRAYED);
  469.     toolbarModifyState(ghWndToolBar, BTN_LIVE, 
  470.         gbHaveHardware ? BTNST_UP : BTNST_GRAYED);
  471.     // Is overlay supported?
  472.     toolbarModifyState(ghWndToolBar, BTN_OVERLAY, 
  473.         (gbHaveHardware && gCapDriverCaps.fHasOverlay) ? 
  474.         BTNST_UP : BTNST_GRAYED);
  475.     // Can the device create palettes?
  476.     toolbarModifyState(ghWndToolBar, BTN_CAPPAL, 
  477.         (gbHaveHardware && gCapDriverCaps.fDriverSuppliesPalettes) ? 
  478.         BTNST_UP : BTNST_GRAYED);
  479.     // Check the appropriate driver in the Options menu
  480.     hMenu = GetMenu (hwnd);
  481.     for (uI = 0; uI < gDriverCount; uI++) {
  482.         CheckMenuItem (hMenu, IDM_O_DRIVER0 + uI, 
  483.                 MF_BYCOMMAND | ((uIndex == uI) ? MF_CHECKED : MF_UNCHECKED));
  484.     } 
  485.     // Unlike all other capture drivers, Scrncap.drv needs to use
  486.     // a Yield callback, and we don't want to abort on mouse clicks,
  487.     // so determine if the current driver is Scrncap.drv
  488.     capGetDriverDescription (uIndex, 
  489.                 szName, sizeof (szName),
  490.                 szVersion, sizeof (szVersion));
  491.     // Set a flag if we're using Scrncap.drv
  492.     gbIsScrncap = (BOOL) _fstrstr (szName, "Screen Capture");
  493.     // Get video format and adjust capture window
  494.     vidcapLayout(ghWndMain);
  495.     InvalidateRect(ghWndMain, NULL, TRUE);
  496.     // set the preview rate (units are millisecs)
  497.     capPreviewRate(hwndCap, gbHaveHardware ? 33 : 0); 
  498.     // set live/overlay to default
  499.     vidcapSetLive(gbLive);
  500.     vidcapSetOverlay(gbOverlay);
  501.     strcat (szName, ",   ");
  502.     strcat (szName, szVersion);
  503.     statusUpdateStatus(ghWndStatus, 
  504.         gbHaveHardware ? szName : gachLastError);
  505.     return gbHaveHardware;
  506. }
  507. /*
  508.  * layout the main window. Put the toolbar at the top and the status
  509.  * line at the bottom, and then give all the rest to vidframe,
  510.  *  - it will centre or scroll the AVICAP window appropriately.
  511.  */
  512. void
  513. vidcapLayout(HWND hwnd)
  514. {
  515.     RECT rc;
  516.     RECT rw;
  517.     int cy;
  518.     int cyBorder, cxBorder;
  519.     int cyTotal;
  520.     int cxToolbar;
  521.     int cyMenuAndToolbarAndCaption;
  522.     gbInLayout = TRUE;  // So that we process WM_GETMINMAXINFO normally
  523.     /* for both the toolbar and status bar window,
  524.      * we want just one of the four borders. We do this
  525.      * by setting the WS_BORDER style, and sizing and positioning
  526.      * the window so that the 3 unwanted borders are outside the parent.
  527.      */
  528.     cyBorder = GetSystemMetrics(SM_CYBORDER);
  529.     cxBorder = GetSystemMetrics(SM_CXBORDER);
  530.     // Figure out the height of the menu, toolbar, and caption
  531.     GetWindowRect (hwnd, &rw);
  532.     GetClientRect (hwnd, &rc);
  533.     ClientToScreen (hwnd, (LPPOINT) &rc);
  534.     cyMenuAndToolbarAndCaption = (rc.top - rw.top) + TOOLBAR_HEIGHT;
  535.     cxToolbar = aPos[APP_NUMTOOLS - 1] + BUTTONWIDTH * 3;
  536.     if (gbAutoSizeFrame && gbHaveHardware && gCapStatus.uiImageWidth) {
  537.         cyTotal = gCapStatus.uiImageHeight +
  538.                 cyMenuAndToolbarAndCaption +
  539.                 (gbStatusBar ? statusGetHeight() : 0) +
  540.                 cyBorder * 2 + 
  541.                 12;     // vidFrame height
  542.         // Never make the frame smaller than the toolbar
  543.         if (gCapStatus.uiImageWidth >= (UINT) cxToolbar) {
  544.             SetWindowPos(
  545.                 hwnd,
  546.                 0, // placement-order handle
  547.                 0, // horizontal position
  548.                 0, // vertical position
  549.                 gCapStatus.uiImageWidth + cxBorder * 24, // width
  550.                 cyTotal, // height
  551.                 SWP_NOZORDER | SWP_NOMOVE  // window-positioning flags
  552.                 );
  553.         } else {
  554.             SetWindowPos(
  555.                 hwnd,
  556.                 0, // placement-order handle
  557.                 0, // horizontal position
  558.                 0, // vertical position
  559.                 cxToolbar, // width
  560.                 cyTotal, // height
  561.                 SWP_NOZORDER | SWP_NOMOVE  // window-positioning flags
  562.                 );
  563.         }
  564.     }
  565.     GetClientRect(hwnd, &rc);
  566.     if (gbToolBar) {
  567.         // put the toolbar at the top - in fact, just off the top so as to
  568.         // hide it's border
  569.         MoveWindow(
  570.             ghWndToolBar,
  571.             -cxBorder, -cyBorder,
  572.             RECTWIDTH(rc)+ (cxBorder * 2),
  573.             TOOLBAR_HEIGHT,
  574.             TRUE);
  575.         rc.top += (TOOLBAR_HEIGHT - cyBorder);
  576.     } else {
  577.         MoveWindow(ghWndToolBar, 0, 0, 0, 0, TRUE);
  578.     }
  579.     // status bar at the bottom
  580.     if (gbStatusBar) {
  581.         cy = statusGetHeight() + cyBorder;
  582.         MoveWindow(
  583.             ghWndStatus,
  584.             -cxBorder, rc.bottom - cy,
  585.             RECTWIDTH(rc) + (2 * cxBorder), cy + cyBorder,
  586.             TRUE);
  587.         rc.bottom -= cy;
  588.     } else {
  589.         MoveWindow(ghWndStatus, 0, 0, 0, 0, TRUE);
  590.     }
  591.     // rest of window goes to vidframe window
  592.     MoveWindow(
  593.         ghWndFrame,
  594.         rc.left, rc.top,
  595.         RECTWIDTH(rc), RECTHEIGHT(rc),
  596.         TRUE);
  597.     // Always layout the frame window, since it is aligned on a
  598.     // DWORD boundary for maximum codec drawing efficiency
  599.     vidframeLayout(ghWndFrame, ghWndCap);
  600.     gbInLayout = FALSE; 
  601. }
  602. /*
  603.  * initialise settings from the profile used before window creation time
  604.  */
  605. void
  606. vidcapReadProfile(void)
  607. {
  608.     // read defaults out of the registry
  609.     gbCentre = mmGetProfileFlag(gachAppTitle, "CenterImage", TRUE);
  610.     gbToolBar = mmGetProfileFlag(gachAppTitle, "ToolBar", TRUE);
  611.     gbStatusBar = mmGetProfileFlag(gachAppTitle, "StatusBar", TRUE);
  612.     gbAutoSizeFrame = mmGetProfileFlag(gachAppTitle, "AutoSizeFrame", TRUE);
  613.     gBackColour = mmGetProfileInt(gachAppTitle, "BackgroundColor", IDD_PrefsLtGrey);
  614.     gWinX = mmGetProfileInt(gachAppTitle, "WindowXPos", (UINT) CW_USEDEFAULT);
  615. if (gWinX != (UINT) CW_USEDEFAULT)
  616.      gWinX = LimitRange(gWinX, 0, GetSystemMetrics (SM_CXSCREEN) - 40);
  617.     gWinY = mmGetProfileInt(gachAppTitle, "WindowYPos", 0);
  618.     gWinY = LimitRange(gWinY, 0, GetSystemMetrics (SM_CYSCREEN) - 40);
  619.     gWinCX = mmGetProfileInt(gachAppTitle, "WindowWidth", 320);
  620.     gWinCX = LimitRange(gWinCX, 20, GetSystemMetrics (SM_CXSCREEN));
  621.     gWinCY = mmGetProfileInt(gachAppTitle, "WindowHeight", 240);
  622.     gWinCY = LimitRange(gWinCY, 20, GetSystemMetrics (SM_CYSCREEN));
  623.     gWinShow = mmGetProfileInt(gachAppTitle, "WindowShow", SW_SHOWDEFAULT);
  624.     gWinShow = LimitRange(gWinShow, SW_SHOWNORMAL, SW_SHOWDEFAULT);
  625.     gbOverlay = mmGetProfileInt(gachAppTitle, "OverlayWindow", FALSE);
  626.     gbLive = mmGetProfileInt(gachAppTitle, "LiveWindow", TRUE);
  627. }
  628. void
  629. vidcapWriteProfile(void)
  630. {
  631.     mmWriteProfileFlag(gachAppTitle, "CenterImage", gbCentre, TRUE);
  632.     mmWriteProfileFlag(gachAppTitle, "ToolBar", gbToolBar, TRUE);
  633.     mmWriteProfileFlag(gachAppTitle, "StatusBar", gbStatusBar, TRUE);
  634.     mmWriteProfileFlag(gachAppTitle, "AutoSizeFrame", gbAutoSizeFrame, TRUE);
  635.     mmWriteProfileInt(gachAppTitle,  "BackgroundColor", gBackColour, IDD_PrefsLtGrey);
  636.     mmWriteProfileInt(gachAppTitle, "WindowXPos", gWinX, (UINT) CW_USEDEFAULT);
  637.     mmWriteProfileInt(gachAppTitle, "WindowYPos", gWinY, 0);
  638.     mmWriteProfileInt(gachAppTitle, "WindowWidth", gWinCX, 320);
  639.     mmWriteProfileInt(gachAppTitle, "WindowHeight", gWinCY, 240);
  640.     mmWriteProfileInt(gachAppTitle, "WindowShow", gWinShow, SW_SHOWDEFAULT);
  641.     mmWriteProfileInt(gachAppTitle, "OverlayWindow", gbOverlay, FALSE);
  642.     mmWriteProfileInt(gachAppTitle, "LiveWindow", gbLive, TRUE);
  643. }
  644. /*
  645.  * initialise settings from the profile used AFTER window creation time
  646.  */
  647. void
  648. vidcapReadSettingsProfile(void)
  649. {
  650.     DWORD dwSize;
  651.     
  652.     mmGetProfileString(gachAppTitle, "CaptureFile", "",
  653.         gachCaptureFile, sizeof(gachCaptureFile));
  654.     mmGetProfileString(gachAppTitle, "MCIDevice", "VideoDisc",
  655.                 gachMCIDeviceName, sizeof(gachMCIDeviceName));
  656.     gCapParms.dwRequestMicroSecPerFrame = 
  657.                 mmGetProfileInt(gachAppTitle, "MicroSecPerFrame", 
  658.                 DEF_CAPTURE_RATE);
  659.     gCapParms.dwRequestMicroSecPerFrame = 
  660.                 mmGetProfileInt(gachAppTitle, "MicroSecPerFrame", 
  661.                 DEF_CAPTURE_RATE);
  662.     gCapParms.fCaptureAudio = mmGetProfileFlag(gachAppTitle, "CaptureAudio", 
  663.                 gCapStatus.fAudioHardware);
  664.     gCapParms.fLimitEnabled = mmGetProfileFlag(gachAppTitle, "LimitEnabled", 
  665.                 FALSE);
  666.     gCapParms.wTimeLimit = 
  667.                 mmGetProfileInt(gachAppTitle, "TimeLimit", 30);
  668.     gCapParms.fMCIControl= mmGetProfileFlag(gachAppTitle, "MCIControl", FALSE);
  669.     gCapParms.fStepMCIDevice= mmGetProfileFlag(gachAppTitle, "StepMCIDevice", FALSE);
  670.     gCapParms.dwMCIStartTime = 
  671.                 mmGetProfileInt(gachAppTitle, "MCIStartTime", 10000);
  672.     gCapParms.dwMCIStopTime = 
  673.                 mmGetProfileInt(gachAppTitle, "MCIStopTime", 20000);
  674.     gCapParms.fStepCaptureAt2x = mmGetProfileFlag(gachAppTitle, "StepCapture2x", 
  675.                 FALSE);
  676.     gCapParms.wStepCaptureAverageFrames = 
  677.                 mmGetProfileInt(gachAppTitle, "StepCaptureAverageFrames", 3);
  678.     gCapParms.AVStreamMaster = mmGetProfileInt (gachAppTitle, "AVStreamMaster",
  679.                 AVSTREAMMASTER_AUDIO);
  680.     gCapParms.fUsingDOSMemory = mmGetProfileFlag (gachAppTitle, "CaptureToDisk",
  681.                 TRUE);
  682.     gCapParms.dwIndexSize = 
  683.                 mmGetProfileInt(gachAppTitle, "IndexSize", 
  684.                 CAP_SMALL_INDEX);
  685.     
  686.     // Retrieve the saved audio format
  687.     // Ask the ACM what the largest known wave format is
  688.     acmMetrics(NULL,
  689.                ACM_METRIC_MAX_SIZE_FORMAT,
  690.                &dwSize);
  691.     // If a wave format was saved in the registry, use that size
  692.     dwSize = max (dwSize, mmGetProfileBinary(gachAppTitle, "WaveFormatBinary",
  693.    NULL,
  694.    NULL,
  695.    0));
  696.   
  697.     if (glpwfex = (LPWAVEFORMATEX) GlobalAllocPtr(GHND, dwSize)) {
  698. capGetAudioFormat(ghWndCap, glpwfex, (WORD)dwSize) ;
  699. mmGetProfileBinary(gachAppTitle, "WaveFormatBinary",
  700.    glpwfex,
  701.    glpwfex,
  702.    dwSize);
  703. // Do some sanity checking
  704. if (MMSYSERR_NOERROR == waveInOpen (NULL, WAVE_MAPPER,
  705.     glpwfex, 0, 0, WAVE_FORMAT_QUERY)) {
  706.     capSetAudioFormat(ghWndCap, glpwfex, (WORD)dwSize) ;
  707. GlobalFreePtr(glpwfex) ;
  708.     }
  709. }
  710. void
  711. vidcapWriteSettingsProfile(void)
  712. {
  713.     mmWriteProfileString(gachAppTitle, "CaptureFile", gachCaptureFile);
  714.     mmWriteProfileString(gachAppTitle, "MCIDevice", gachMCIDeviceName);
  715.     mmWriteProfileInt(gachAppTitle, "MicroSecPerFrame", 
  716.                 gCapParms.dwRequestMicroSecPerFrame, DEF_CAPTURE_RATE);
  717.     mmWriteProfileFlag(gachAppTitle, "CaptureAudio", 
  718.                 gCapParms.fCaptureAudio, gCapStatus.fAudioHardware);
  719.     mmWriteProfileFlag(gachAppTitle, "LimitEnabled", 
  720.                 gCapParms.fLimitEnabled, FALSE);
  721.     mmWriteProfileInt(gachAppTitle, "TimeLimit", 
  722.                 gCapParms.wTimeLimit, 30);
  723.     mmWriteProfileFlag(gachAppTitle, "MCIControl", 
  724.                 gCapParms.fMCIControl, FALSE);
  725.     mmWriteProfileFlag(gachAppTitle, "StepMCIDevice", 
  726.                 gCapParms.fStepMCIDevice, FALSE);
  727.     mmWriteProfileInt(gachAppTitle, "MCIStartTime", 
  728.                 gCapParms.dwMCIStartTime, 10000);
  729.     mmWriteProfileInt(gachAppTitle, "MCIStopTime", 
  730.                 gCapParms.dwMCIStopTime, 20000);
  731.     mmWriteProfileFlag(gachAppTitle, "StepCapture2x", 
  732.                 gCapParms.fStepCaptureAt2x, FALSE);
  733.     mmWriteProfileInt(gachAppTitle, "StepCaptureAverageFrames", 
  734.                 gCapParms.wStepCaptureAverageFrames, 3);
  735.     mmWriteProfileInt(gachAppTitle, "AVStreamMaster", 
  736.                 gCapParms.AVStreamMaster, AVSTREAMMASTER_AUDIO);
  737.     mmWriteProfileFlag(gachAppTitle, "CaptureToDisk", 
  738.                 gCapParms.fUsingDOSMemory, TRUE);
  739.     mmWriteProfileInt(gachAppTitle, "IndexSize", 
  740.                 gCapParms.dwIndexSize, CAP_SMALL_INDEX);
  741.     // The audio format is written whenever it is changed via dlg
  742. }
  743. /* --- error/status functions -------------------------------------------*/
  744. /*
  745.  * put up a message box loading a string from the
  746.  * resource file
  747.  */
  748. int
  749. MessageBoxID(UINT idString, UINT fuStyle)
  750. {
  751.     char achMessage[256];   // max message length
  752.     LoadString(ghInstApp, idString, achMessage, sizeof(achMessage));
  753.     return MessageBox(ghWndMain, achMessage, gachAppTitle, fuStyle);
  754. }
  755. //
  756. // ErrorCallbackProc: Error Callback Function
  757. //
  758. LRESULT FAR PASCAL ErrorCallbackProc(HWND hWnd, int nErrID, LPSTR lpErrorText)
  759. {
  760. ////////////////////////////////////////////////////////////////////////
  761. //  hWnd:          Application main window handle
  762. //  nErrID:        Error code for the encountered error
  763. //  lpErrorText:   Error text string for the encountered error
  764. ////////////////////////////////////////////////////////////////////////
  765.     if (!ghWndMain)
  766.         return FALSE;
  767.     if (nErrID == 0)            // Starting a new major function
  768.         return TRUE;            // Clear out old errors...
  769.     // save the error message for use in NoHardwareDlgProc
  770.     lstrcpy(gachLastError, lpErrorText);
  771.     // Show the error ID and text
  772.     MessageBox(hWnd, lpErrorText, gachAppTitle,
  773.                 MB_OK | MB_ICONEXCLAMATION) ;
  774.     return (LRESULT) TRUE ;
  775. }
  776. //
  777. // StatusCallbackProc: Status Callback Function
  778. //
  779. LRESULT FAR PASCAL StatusCallbackProc(HWND hWnd, int nID, LPSTR lpStatusText)
  780. {
  781. ////////////////////////////////////////////////////////////////////////
  782. //  hWnd:           Application main window handle
  783. //  nID:            Status code for the current status
  784. //  lpStatusText:   Status text string for the current status
  785. ////////////////////////////////////////////////////////////////////////
  786.     static int CurrentID;
  787.     if (!ghWndMain) {
  788.         return FALSE;
  789.     }
  790.     // the CAP_END message sometimes overwrites a useful
  791.     // statistics message.
  792.     if (nID == IDS_CAP_END) {
  793.         if ((CurrentID == IDS_CAP_STAT_VIDEOAUDIO) ||
  794.             (CurrentID == IDS_CAP_STAT_VIDEOONLY)) {
  795.             return(TRUE);
  796.         }
  797.     }
  798.     CurrentID = nID;
  799.     statusUpdateStatus(ghWndStatus, lpStatusText);
  800.     return (LRESULT) TRUE ;
  801. }
  802. //
  803. // YieldCallbackProc: Status Callback Function
  804. // (Only used for Scrncap.drv driver)
  805. //
  806. LRESULT FAR PASCAL YieldCallbackProc(HWND hWnd)
  807. {
  808. ////////////////////////////////////////////////////////////////////////
  809. //  hWnd:           Application main window handle
  810. ////////////////////////////////////////////////////////////////////////
  811.     MSG msg;
  812.     if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
  813.         TranslateMessage(&msg);
  814.         DispatchMessage(&msg);
  815.     }
  816.     // Return TRUE to continue capturing
  817.     return (LRESULT) TRUE;
  818. }
  819. /*
  820.  * load a string from the string table and return
  821.  * a pointer to it for temporary use. Each call
  822.  * overwrites the previous
  823.  */
  824. LPSTR
  825. tmpString(UINT idString)
  826. {
  827.     static char ach[350];
  828.     LoadString(ghInstApp, idString, ach, sizeof(ach));
  829.     // ensure null terminated
  830.     ach[sizeof(ach) -1] = 0;
  831.     return(ach);
  832. }
  833. /* --- connect to and init hardware ------------------------------------- */
  834. void
  835. vidcapSetLive(BOOL bLive)
  836. {
  837.     capPreview(ghWndCap, bLive);
  838.     toolbarModifyState(ghWndToolBar, BTN_LIVE, bLive? BTNST_DOWN : BTNST_UP);
  839.     CheckMenuItem(GetMenu(ghWndMain), IDM_O_PREVIEW,
  840.         MF_BYCOMMAND | (bLive ? MF_CHECKED : MF_UNCHECKED));
  841.     gbLive = bLive;
  842.     if (bLive == TRUE) {
  843.         vidcapSetOverlay(FALSE);
  844.     }
  845. }
  846. void
  847. vidcapSetOverlay(BOOL bOverlay)
  848. {
  849.     if (!gCapDriverCaps.fHasOverlay) {
  850.         CheckMenuItem(GetMenu(ghWndMain), IDM_O_OVERLAY,
  851.             MF_BYCOMMAND | MF_UNCHECKED);
  852.         gbOverlay = FALSE;
  853.         return;
  854.     }
  855.     capOverlay(ghWndCap, bOverlay);
  856.     toolbarModifyState(ghWndToolBar, BTN_OVERLAY, bOverlay ? BTNST_DOWN : BTNST_UP);
  857.     CheckMenuItem(GetMenu(ghWndMain), IDM_O_OVERLAY,
  858.         MF_BYCOMMAND | (bOverlay ? MF_CHECKED : MF_UNCHECKED));
  859.     gbOverlay = bOverlay;
  860.     if (bOverlay == TRUE) {
  861.         vidcapSetLive(FALSE);
  862.     }
  863. }
  864. void
  865. vidcapSetCaptureFile(LPSTR pFileName)
  866. {
  867.     char achBuffer[_MAX_PATH];
  868.     if ((pFileName != NULL) && (lstrlen(pFileName)  > 0)) {
  869.         // record the capture filename
  870.         if (lstrcmp(gachCaptureFile, pFileName)) {
  871.             lstrcpy(gachCaptureFile, pFileName);
  872.         }
  873.         // and set window title
  874.         wsprintf(achBuffer, "%s - %s", gachAppTitle, pFileName);
  875.     } else {
  876.         gachCaptureFile[0] = 0;
  877.         lstrcpy(achBuffer, gachAppTitle);
  878.     }
  879.     capFileSetCaptureFile(ghWndCap, gachCaptureFile);
  880.     SetWindowText(ghWndMain, achBuffer);
  881. }
  882. /* --- winproc and message handling --------------------------------------- */
  883. /*
  884.  * called from WM_COMMAND processing if the
  885.  * message is from the toolbar. iButton contains the
  886.  * button ID in the lower 8 bits, and the flags in the upper 8 bits/
  887.  */
  888. LONG FAR PASCAL
  889. toolbarCommand (HWND hWnd, int iButton, HWND hwndToolbar)
  890. {
  891.     int iBtnPos, iState, iActivity, iString;
  892.     // check repeat bit
  893.     if (iButton & BTN_REPEAT) {
  894.         return(0);
  895.     }
  896.     iButton &= 0xff;
  897.     iBtnPos = toolbarIndexFromButton(hwndToolbar, iButton);
  898.     iState = toolbarStateFromButton(hwndToolbar, iButton);
  899.     iActivity = toolbarActivityFromButton(hwndToolbar, iButton);
  900.     iString = toolbarStringFromIndex(hwndToolbar, iBtnPos);
  901.     switch(iActivity) {
  902.     case BTNACT_MOUSEDOWN:
  903.     case BTNACT_KEYDOWN:
  904.     case BTNACT_MOUSEMOVEON:
  905.         statusUpdateStatus(ghWndStatus, MAKEINTRESOURCE(iString));
  906.         break;
  907.     case BTNACT_MOUSEMOVEOFF:
  908.         statusUpdateStatus(ghWndStatus, NULL);
  909.         break;
  910.     case BTNACT_MOUSEUP:
  911.     case BTNACT_KEYUP:
  912.         statusUpdateStatus(ghWndStatus, NULL);
  913.         switch(iButton) {
  914.         case BTN_SETFILE:
  915.             SendMessage(hWnd, WM_COMMAND,
  916.                 GET_WM_COMMAND_MPS(IDM_F_SETCAPTUREFILE, NULL, 0));
  917.                 break;
  918.         case BTN_EDITCAP:
  919.             // edit captured video
  920.             SendMessage(hWnd, WM_COMMAND,
  921.                 GET_WM_COMMAND_MPS(IDM_F_EDITVIDEO, NULL, 0));
  922.             break;
  923.         case BTN_LIVE:
  924.             SendMessage(hWnd,WM_COMMAND,
  925.                 GET_WM_COMMAND_MPS(IDM_O_PREVIEW, NULL, 0));
  926.             break;
  927.         case BTN_CAPFRAME:
  928.             SendMessage(hWnd, WM_COMMAND,
  929.                 GET_WM_COMMAND_MPS(IDM_C_CAPTUREFRAME, NULL, 0));
  930.             break;
  931.         case BTN_CAPSEL:
  932.             // capture selected frames
  933.             SendMessage(hWnd, WM_COMMAND,
  934.                 GET_WM_COMMAND_MPS(IDM_C_CAPSEL, NULL, 0));
  935.             break;
  936.         case BTN_CAPAVI:
  937.             SendMessage(hWnd,WM_COMMAND,
  938.                 GET_WM_COMMAND_MPS(IDM_C_CAPTUREVIDEO, NULL, 0));
  939.             break;
  940.         case BTN_CAPPAL:
  941.             SendMessage(hWnd, WM_COMMAND,
  942.                 GET_WM_COMMAND_MPS(IDM_C_PALETTE, NULL, 0));
  943.             break;
  944.         case BTN_OVERLAY:
  945.             SendMessage(hWnd, WM_COMMAND,
  946.                 GET_WM_COMMAND_MPS(IDM_O_OVERLAY, NULL, 0));
  947.             break;
  948.         }
  949.         break;
  950.     }
  951.     return(0);
  952. }
  953. /*
  954.  * Put up a dialog to allow the user to select a capture file.
  955.  */
  956. LONG FAR PASCAL
  957. cmdSetCaptureFile(HWND hWnd)
  958. {
  959.     OPENFILENAME ofn ;
  960.     LPSTR p;
  961.     char         achFileName[_MAX_PATH];
  962.     char         achBuffer[_MAX_PATH] ;
  963.     UINT         wError ;
  964.     HANDLE hFilter;
  965.     int oldhelpid;
  966.     // Get current capture file name and
  967.     // then try to get the new capture file name
  968.     if (wError = capFileGetCaptureFile(ghWndCap, achFileName,
  969.                                 sizeof(achFileName))) {
  970.         // Get just the path info
  971.         // Terminate the full path at the last backslash
  972.         lstrcpy (achBuffer, achFileName);
  973.         for (p = achBuffer + lstrlen(achBuffer); p > achBuffer; p--) {
  974.             if (*p == '\') {
  975.                 *(p+1) = '';
  976.                 break;
  977.             }
  978.         }
  979.         _fmemset(&ofn, 0, sizeof(OPENFILENAME)) ;
  980.         ofn.lStructSize = sizeof(OPENFILENAME) ;
  981.         ofn.hwndOwner = hWnd ;
  982.         //load filters from resource stringtable
  983.         hFilter = FindResource(ghInstApp, MAKEINTRESOURCE(ID_FILTER_AVI), RT_RCDATA);
  984.         if ((hFilter = LoadResource(ghInstApp, hFilter)) == NULL) {
  985.             ofn.lpstrFilter = NULL;
  986.         } else {
  987.             ofn.lpstrFilter = LockResource(hFilter);
  988.         }
  989.         ofn.nFilterIndex = 0 ;
  990.         ofn.lpstrFile = achFileName ;
  991.         ofn.nMaxFile = sizeof(achFileName) ;
  992.         ofn.lpstrFileTitle = NULL;
  993.         ofn.lpstrTitle = tmpString(IDS_TITLE_SETCAPTUREFILE);
  994.         ofn.nMaxFileTitle = 0 ;
  995.         ofn.lpstrInitialDir = achBuffer;
  996.         ofn.Flags =
  997.         OFN_HIDEREADONLY |
  998.         OFN_NOREADONLYRETURN |
  999.         OFN_PATHMUSTEXIST ;
  1000.         // set help context for dialog
  1001.         oldhelpid = SetCurrentHelpContext(IDA_SETCAPFILE);
  1002.         if (GetOpenFileName(&ofn)) {
  1003.             OFSTRUCT os;
  1004.             vidcapSetCaptureFile(achFileName);
  1005.             /*
  1006.              * if this is a new file, then invite the user to
  1007.              * allocate some space
  1008.              */
  1009.             if (OpenFile(achFileName, &os, OF_EXIST) == HFILE_ERROR) {
  1010.                 /*
  1011.                  * show the allocate file space dialog to encourage
  1012.                  * the user to pre-allocate space
  1013.                  */
  1014.                 if (DoDialog(hWnd, IDD_AllocCapFileSpace, AllocCapFileProc, 0)) {
  1015.     // ensure repaint after dismissing dialog before
  1016.     // possibly lengthy operation
  1017.     UpdateWindow(ghWndMain);
  1018.                     // If user has hit OK then alloc requested capture file space
  1019.                     if (! capFileAlloc(ghWndCap, (long) gwCapFileSize * ONEMEG)) {
  1020.                         MessageBoxID(IDS_ERR_CANT_PREALLOC,
  1021.                                     MB_OK | MB_ICONEXCLAMATION) ;
  1022.                     }
  1023.                 }
  1024.             }
  1025.         }
  1026.         // restore old help context
  1027.         SetCurrentHelpContext(oldhelpid);
  1028.         if (hFilter) {
  1029.             UnlockResource(hFilter);
  1030.         }
  1031.     }
  1032.     return(0);
  1033. }
  1034. /*
  1035.  * query the user for a filename, and then save the captured video
  1036.  * to that file
  1037.  */
  1038. LONG FAR PASCAL
  1039. cmdSaveVideoAs(HWND hWnd)
  1040. {
  1041.     OPENFILENAME ofn ;
  1042.     char         achFileName[_MAX_PATH];
  1043.     UINT         wError ;
  1044.     HANDLE       hFilter;
  1045.     int          oldhelpid;
  1046.     // Get the current capture file name and
  1047.     // then get the substitute file name to save video in
  1048.     if (wError = capFileGetCaptureFile(ghWndCap, achFileName, sizeof(achFileName))) {
  1049.         _fmemset(&ofn, 0, sizeof(OPENFILENAME)) ;
  1050.         ofn.lStructSize = sizeof(OPENFILENAME) ;
  1051.         ofn.hwndOwner = hWnd ;
  1052.         //load filters from resource stringtable
  1053.         hFilter = FindResource(ghInstApp, MAKEINTRESOURCE(ID_FILTER_AVI), RT_RCDATA);
  1054.         if ((hFilter = LoadResource(ghInstApp, hFilter)) == NULL) {
  1055.             ofn.lpstrFilter = NULL;
  1056.         } else {
  1057.             ofn.lpstrFilter = LockResource(hFilter);
  1058.         }
  1059.         ofn.nFilterIndex = 0 ;
  1060.         ofn.lpstrFile = achFileName ;
  1061.         ofn.nMaxFile = sizeof(achFileName) ;
  1062.         ofn.lpstrFileTitle = NULL ;
  1063.         ofn.lpstrTitle = tmpString(IDS_TITLE_SAVEAS);
  1064.         ofn.nMaxFileTitle = 0 ;
  1065.         ofn.lpstrInitialDir = NULL ;
  1066.         ofn.Flags =
  1067.         OFN_OVERWRITEPROMPT |  OFN_PATHMUSTEXIST ;
  1068.         // set help context
  1069.         oldhelpid = SetCurrentHelpContext(IDA_SAVECAPFILE);
  1070.         if (GetSaveFileName(&ofn)) {
  1071.             // If the user has hit OK then set save file name
  1072.             capFileSaveAs(ghWndCap, achFileName) ;
  1073.         }
  1074.         SetCurrentHelpContext(oldhelpid);
  1075.         if (hFilter) {
  1076.             UnlockResource(hFilter);
  1077.         }
  1078.     }
  1079.     return(0);
  1080. }
  1081. /*
  1082.  * Put up a dialog to allow the user to select a palette file and then
  1083.  * load that palette
  1084.  */
  1085. LONG FAR PASCAL
  1086. cmdLoadPalette(HWND hWnd)
  1087. {
  1088.     OPENFILENAME ofn ;
  1089.     char         achFileName[_MAX_PATH];
  1090.     HANDLE       hFilter;
  1091.     int          oldhelpid;
  1092.     achFileName[0] = 0;
  1093.     _fmemset(&ofn, 0, sizeof(OPENFILENAME));
  1094.     ofn.lStructSize = sizeof(OPENFILENAME);
  1095.     ofn.hwndOwner = hWnd;
  1096.     //load filters from resource stringtable
  1097.     hFilter = FindResource(ghInstApp, MAKEINTRESOURCE(ID_FILTER_PALETTE), RT_RCDATA);
  1098.     if ((hFilter = LoadResource(ghInstApp, hFilter)) == NULL) {
  1099.         ofn.lpstrFilter = NULL;
  1100.     } else {
  1101.         ofn.lpstrFilter = LockResource(hFilter);
  1102.     }
  1103.     ofn.nFilterIndex = 1;
  1104.     ofn.lpstrFile = achFileName;
  1105.     ofn.nMaxFile = sizeof(achFileName);
  1106.     ofn.lpstrFileTitle = NULL;
  1107.     ofn.lpstrTitle = tmpString(IDS_TITLE_LOADPALETTE);
  1108.     ofn.nMaxFileTitle = 0;
  1109.     ofn.lpstrInitialDir = NULL;
  1110.     ofn.Flags =
  1111.     OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
  1112.     // set help context id
  1113.     oldhelpid = SetCurrentHelpContext(IDA_LOADPAL);
  1114.     if (GetOpenFileName(&ofn)) {
  1115.         // If the user has hit OK then load palette
  1116.         capPaletteOpen(ghWndCap, achFileName);
  1117.     }
  1118.     SetCurrentHelpContext(oldhelpid);
  1119.     if (hFilter) {
  1120.         UnlockResource(hFilter);
  1121.     }
  1122.     return(0);
  1123. }
  1124. /*
  1125.  * query the user for a filename, and then save the current palette
  1126.  * to that file
  1127.  */
  1128. LONG FAR PASCAL
  1129. cmdSavePalette(HWND hWnd)
  1130. {
  1131.     OPENFILENAME ofn ;
  1132.     char         achFileName[_MAX_PATH];
  1133.     HANDLE       hFilter;
  1134.     int          oldhelpid;
  1135.     achFileName[0] = 0;
  1136.     _fmemset(&ofn, 0, sizeof(OPENFILENAME)) ;
  1137.     ofn.lStructSize = sizeof(OPENFILENAME) ;
  1138.     ofn.hwndOwner = hWnd ;
  1139.     //load filters from resource stringtable
  1140.     hFilter = FindResource(ghInstApp, MAKEINTRESOURCE(ID_FILTER_PALETTE), RT_RCDATA);
  1141.     if ((hFilter = LoadResource(ghInstApp, hFilter)) == NULL) {
  1142.         ofn.lpstrFilter = NULL;
  1143.     } else {
  1144.         ofn.lpstrFilter = LockResource(hFilter);
  1145.     }
  1146.     ofn.nFilterIndex = 1;
  1147.     ofn.lpstrFile = achFileName;
  1148.     ofn.nMaxFile = sizeof(achFileName);
  1149.     ofn.lpstrFileTitle = NULL;
  1150.     ofn.lpstrTitle = tmpString(IDS_TITLE_SAVEPALETTE);
  1151.     ofn.nMaxFileTitle = 0;
  1152.     ofn.lpstrInitialDir = NULL;
  1153.     ofn.Flags =
  1154.     OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
  1155.     // set help context for F1 key
  1156.     oldhelpid = SetCurrentHelpContext(IDA_SAVEPAL);
  1157.     if (GetSaveFileName(&ofn)) {
  1158.         // If the user has hit OK then set save file name
  1159.         capPaletteSave(ghWndCap, achFileName);
  1160.     }
  1161.     SetCurrentHelpContext(oldhelpid);
  1162.     if (hFilter) {
  1163.         UnlockResource(hFilter);
  1164.     }
  1165.     return(0);
  1166. }
  1167. /*
  1168.  * query the user for a filename, and then save the current frame
  1169.  * to that file
  1170.  */
  1171. LONG FAR PASCAL
  1172. cmdSaveDIB(HWND hWnd)
  1173. {
  1174.     OPENFILENAME ofn ;
  1175.     char         achFileName[_MAX_PATH];
  1176.     HANDLE       hFilter;
  1177.     int          oldhelpid;
  1178.     achFileName[0] = 0;
  1179.     _fmemset(&ofn, 0, sizeof(OPENFILENAME)) ;
  1180.     ofn.lStructSize = sizeof(OPENFILENAME) ;
  1181.     ofn.hwndOwner = hWnd ;
  1182.     //load filters from resource stringtable
  1183.     hFilter = FindResource(ghInstApp, MAKEINTRESOURCE(ID_FILTER_DIB), RT_RCDATA);
  1184.     if ((hFilter = LoadResource(ghInstApp, hFilter)) == NULL) {
  1185.         ofn.lpstrFilter = NULL;
  1186.     } else {
  1187.         ofn.lpstrFilter = LockResource(hFilter);
  1188.     }
  1189.     ofn.nFilterIndex = 1;
  1190.     ofn.lpstrFile = achFileName;
  1191.     ofn.nMaxFile = sizeof(achFileName);
  1192.     ofn.lpstrFileTitle = NULL;
  1193.     ofn.lpstrTitle = tmpString(IDS_TITLE_SAVEDIB);
  1194.     ofn.nMaxFileTitle = 0;
  1195.     ofn.lpstrInitialDir = NULL;
  1196.     ofn.Flags =
  1197.     OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
  1198.     // set help context for F1 handling
  1199.     oldhelpid = SetCurrentHelpContext(IDA_SAVEDIB);
  1200.     if (GetSaveFileName(&ofn)) {
  1201.         // If the user has hit OK then set save file name
  1202.         capFileSaveDIB(ghWndCap, achFileName);
  1203.     }
  1204.     SetCurrentHelpContext(oldhelpid);
  1205.     if (hFilter) {
  1206.         UnlockResource(hFilter);
  1207.     }
  1208.     return(0);
  1209. }
  1210. //
  1211. // MenuProc: Processes All Menu-based Operations
  1212. //
  1213. long FAR PASCAL MenuProc(HWND hWnd, UINT wParam, LONG lParam)
  1214. {
  1215. ////////////////////////////////////////////////////////////////////////
  1216. //  hWnd:      Application main window handle
  1217. //  hMenu:     Application menu handle
  1218. //  wParam:    Menu option
  1219. //  lParam:    Additional info for any menu option
  1220. ////////////////////////////////////////////////////////////////////////
  1221.     BOOL         fResult ;
  1222.     DWORD        dwSize ;
  1223.     int          oldhelpid;
  1224.     HMENU hMenu = GetMenu(hWnd) ;
  1225.     switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  1226. case IDC_TOOLBAR:
  1227.             return toolbarCommand(hWnd, GET_WM_COMMAND_CMD(wParam, lParam), ghWndToolBar);
  1228. /* --- file --- */
  1229.         case IDM_F_SETCAPTUREFILE:
  1230.             return cmdSetCaptureFile(hWnd);
  1231.         case IDM_F_SAVEVIDEOAS:
  1232.             return cmdSaveVideoAs(hWnd);
  1233.             break;
  1234.         case IDM_F_ALLOCATESPACE:
  1235.             if (DoDialog(hWnd, IDD_AllocCapFileSpace, AllocCapFileProc, 0)) {
  1236. // ensure repaint after dismissing dialog before
  1237. // possibly lengthy operation
  1238. UpdateWindow(ghWndMain);
  1239.                 // If user has hit OK then alloc requested capture file space
  1240.                 if (! capFileAlloc(ghWndCap, (long) gwCapFileSize * ONEMEG)) {
  1241.                     MessageBoxID(IDS_ERR_CANT_PREALLOC,
  1242.                                 MB_OK | MB_ICONEXCLAMATION) ;
  1243.                 }
  1244.             }
  1245.             break ;
  1246.         case IDM_F_EXIT:
  1247.             DestroyWindow(hWnd) ;
  1248.             break;
  1249.         case IDM_F_LOADPALETTE:
  1250.             return cmdLoadPalette(hWnd);
  1251.         case IDM_F_SAVEPALETTE:
  1252.             return cmdSavePalette(hWnd);
  1253.         case IDM_F_SAVEFRAME:
  1254.             return cmdSaveDIB(hWnd);
  1255.         case IDM_F_EDITVIDEO:
  1256.         {
  1257.             char achCmdLine[256];
  1258.             UINT        u;
  1259.             BOOL f = TRUE; /* assume the best */
  1260.             HCURSOR     hOldCursor;
  1261.             /* build up the command line "AviEdit -n filename" */
  1262.             if (lstrlen(gachCaptureFile) > 0) {
  1263.                 lstrcpy(achCmdLine,"VIDEdit -n ");
  1264.                 lstrcat(achCmdLine, gachCaptureFile);
  1265.                 hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1266.                 u = WinExec(achCmdLine, SW_SHOWNORMAL);
  1267.                 if (u < 32){
  1268.              /* report error on forking VidEdit */
  1269.                     MessageBoxID(IDS_ERR_VIDEDIT, MB_OK|MB_ICONEXCLAMATION);
  1270.              f = FALSE;
  1271.                 }
  1272.                 SetCursor(hOldCursor);
  1273.             }
  1274.             return f;
  1275.         }
  1276. /* --- edit --- */
  1277.         case IDM_E_COPY:
  1278.             capEditCopy(ghWndCap) ;
  1279.             break;
  1280.         case IDM_E_PASTEPALETTE:
  1281.             capPalettePaste(ghWndCap) ;
  1282.             break;
  1283.         case IDM_E_PREFS:
  1284.             {
  1285.                 if (DoDialog(hWnd, IDD_Prefs, PrefsDlgProc, 0)) {
  1286.                         // write prefs to profile
  1287.                         // force new brush
  1288.                         vidframeSetBrush(ghWndFrame, gBackColour);
  1289.                         // re-do layout
  1290.                         vidcapLayout(hWnd);
  1291.                 }
  1292.             }
  1293.             break;
  1294. /* --- options --- */
  1295.         case IDM_O_PREVIEW:
  1296.             // Toggle Preview
  1297.          capGetStatus(ghWndCap, &gCapStatus, sizeof(CAPSTATUS)) ;
  1298.             vidcapSetLive(!gCapStatus.fLiveWindow) ;
  1299.             break;
  1300.         case IDM_O_OVERLAY:
  1301.             // Toggle Overlay
  1302.          capGetStatus(ghWndCap, &gCapStatus, sizeof(CAPSTATUS)) ;
  1303.             vidcapSetOverlay(!gCapStatus.fOverlayWindow);
  1304.             break ;
  1305.         case IDM_O_AUDIOFORMAT:
  1306. #ifdef  USE_ACM
  1307.             {
  1308.                 ACMFORMATCHOOSE cfmt;
  1309.                 static BOOL fDialogUp = FALSE;
  1310.                 if (fDialogUp)
  1311.                     return FALSE;
  1312.                 fDialogUp = TRUE;
  1313.                 // Ask the ACM what the largest wave format is.....
  1314.                 acmMetrics(NULL,
  1315.                             ACM_METRIC_MAX_SIZE_FORMAT,
  1316.                             &dwSize);
  1317.                 // Get the current audio format
  1318.                 dwSize = max (dwSize, capGetAudioFormatSize (ghWndCap));
  1319.                 if (glpwfex = (LPWAVEFORMATEX) GlobalAllocPtr(GHND, dwSize)) {
  1320.                     capGetAudioFormat(ghWndCap, glpwfex, (WORD)dwSize) ;
  1321.     _fmemset (&cfmt, 0, sizeof (ACMFORMATCHOOSE));
  1322.     cfmt.cbStruct = sizeof (ACMFORMATCHOOSE);
  1323.     cfmt.fdwStyle =  ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT;
  1324.     cfmt.fdwEnum =   ACM_FORMATENUMF_HARDWARE |
  1325.      ACM_FORMATENUMF_INPUT;
  1326.     cfmt.hwndOwner = hWnd;
  1327.     cfmt.pwfx =     glpwfex;
  1328.     cfmt.cbwfx =    dwSize;
  1329.     //oldhelpid = SetCurrentHelpContext(IDA_AUDIOSETUP);
  1330.     if (!acmFormatChoose(&cfmt)) {
  1331. capSetAudioFormat(ghWndCap, glpwfex, (WORD)glpwfex->cbSize +
  1332.   sizeof (WAVEFORMATEX)) ;
  1333. mmWriteProfileBinary(gachAppTitle, "WaveFormatBinary",
  1334.      (LPVOID) glpwfex, glpwfex->cbSize +
  1335.      sizeof (WAVEFORMATEX));
  1336.     }
  1337.     //SetCurrentHelpContext(oldhelpid);
  1338.     GlobalFreePtr(glpwfex) ;
  1339. }
  1340.                 fDialogUp = FALSE;
  1341.             }
  1342. #else
  1343.             {
  1344.                 // Get current audio format and then find required format
  1345.                 dwSize = capGetAudioFormatSize (ghWndCap);  
  1346.                 glpwfex = (LPWAVEFORMATEX) GlobalAllocPtr(GHND, dwSize) ;
  1347.                 capGetAudioFormat(ghWndCap, glpwfex, (WORD)dwSize) ;
  1348.                 if (DoDialog(hWnd, IDD_AudioFormat, AudioFormatProc, 0)) {
  1349.                         // If the user has hit OK, set the new audio format
  1350.                         capSetAudioFormat(ghWndCap, glpwfex, (WORD)dwSize) ;
  1351. mmWriteProfileBinary(gachAppTitle, "WaveFormatBinary",
  1352.  (LPVOID) glpwfex, dwSize);
  1353.                 }
  1354.                 GlobalFreePtr(glpwfex) ;
  1355.             }
  1356. #endif
  1357.             break ;
  1358.         case IDM_O_VIDEOFORMAT:
  1359.             if (gCapDriverCaps.fHasDlgVideoFormat) {
  1360.                 // Only if the driver has a "Video Format" dialog box
  1361.                 oldhelpid = SetCurrentHelpContext(IDA_VIDFORMAT);
  1362.                 if (capDlgVideoFormat(ghWndCap)) {  // If successful,
  1363.                     // Get the new image dimension and center capture window
  1364.                     capGetStatus(ghWndCap, &gCapStatus, sizeof(CAPSTATUS)) ;
  1365.                     vidcapLayout(hWnd);
  1366.                 }
  1367.                 SetCurrentHelpContext(oldhelpid);
  1368.             }
  1369.             break;
  1370.         case IDM_O_VIDEOSOURCE:
  1371.             if (gCapDriverCaps.fHasDlgVideoSource) {
  1372.                 // Only if the driver has a "Video Source" dialog box
  1373.                 oldhelpid = SetCurrentHelpContext(IDA_VIDSOURCE);
  1374.                 capDlgVideoSource(ghWndCap) ;
  1375.                 capGetStatus(ghWndCap, &gCapStatus, sizeof(CAPSTATUS)) ;
  1376.                 vidcapLayout(hWnd);
  1377.                 SetCurrentHelpContext(oldhelpid);
  1378.             }
  1379.             break ;
  1380.         case IDM_O_VIDEODISPLAY:
  1381.             if (gCapDriverCaps.fHasDlgVideoDisplay) {
  1382.                 // Only if the driver has a "Video Display" dialog box
  1383.                 oldhelpid = SetCurrentHelpContext(IDA_VIDDISPLAY);
  1384.                 capDlgVideoDisplay(ghWndCap) ;
  1385.                 capGetStatus(ghWndCap, &gCapStatus, sizeof(CAPSTATUS)) ;
  1386.                 SetCurrentHelpContext(oldhelpid);
  1387.             }
  1388.             break ;
  1389.         case IDM_O_CHOOSECOMPRESSOR:
  1390.             oldhelpid = SetCurrentHelpContext(IDA_COMPRESSION);
  1391.             capDlgVideoCompression(ghWndCap);
  1392.             SetCurrentHelpContext(oldhelpid);
  1393.             break;
  1394.         // Select a driver to activate
  1395.         case IDM_O_DRIVER0:
  1396.         case IDM_O_DRIVER1:
  1397.         case IDM_O_DRIVER2:
  1398.         case IDM_O_DRIVER3:
  1399.         case IDM_O_DRIVER4:
  1400.         case IDM_O_DRIVER5:
  1401.         case IDM_O_DRIVER6:
  1402.         case IDM_O_DRIVER7:
  1403.         case IDM_O_DRIVER8:
  1404.         case IDM_O_DRIVER9:
  1405.             vidcapInitHardware(ghWndMain, ghWndCap, wParam - IDM_O_DRIVER0);
  1406.             break;
  1407. /* --- capture --- */
  1408.         case IDM_C_PALETTE:
  1409.             if (DoDialog(hWnd, IDD_MakePalette, MakePaletteProc, 0)) {
  1410.                 // Palette is created within the dialog
  1411.                 bDefaultPalette = FALSE;
  1412.             }
  1413.             break;
  1414.         case IDM_C_CAPTUREVIDEO:
  1415.             // warn user if he is still using the default palette
  1416.             if (bDefaultPalette) {
  1417. LPBITMAPINFOHEADER lpbi;
  1418. int sz;
  1419. // fUsingDefaultPalette will be TRUE even if the
  1420. // current capture format is non-palettised. This is a
  1421. // bizarre decision of Jay's.
  1422. sz = (int)capGetVideoFormatSize(ghWndCap);
  1423. lpbi = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, sz);
  1424. if (lpbi) {    // We can warn s/he
  1425.     if (capGetVideoFormat(ghWndCap, lpbi, sz) &&
  1426. (lpbi->biCompression == BI_RGB) &&
  1427. (lpbi->biBitCount <= 8)) {
  1428. CAPSTATUS cs;
  1429. // if we've warned him once, we can forget it
  1430. bDefaultPalette = FALSE;
  1431. capGetStatus(ghWndCap, &cs, sizeof(cs));
  1432. if (cs.fUsingDefaultPalette) {
  1433.     if (MessageBoxID(IDS_WARN_DEFAULT_PALETTE,
  1434.              MB_OKCANCEL| MB_ICONEXCLAMATION)== IDCANCEL) {
  1435. break;
  1436.     }
  1437. }
  1438.     }
  1439.     LocalFree(lpbi);
  1440. }
  1441.             }
  1442.             // Invoke a Dlg box to setup all the params
  1443.             if (DoDialog(hWnd, IDD_CapSetUp, CapSetUpProc, 0)) {
  1444.                 // set the defaults we won't bother the user with
  1445.                 gCapParms.fMakeUserHitOKToCapture = !gCapParms.fMCIControl;
  1446.                 gCapParms.wPercentDropForError = 10;
  1447.                 // fUsingDOSMemory is obsolete, but we use it here as
  1448.                 // a flag which is TRUE if "CapturingToDisk"
  1449.                 // The number of video buffers should be enough to get through
  1450.                 // disk seeks and thermal recalibrations if "CapturingToDisk"
  1451.                 // If "CapturingToMemory", get as many buffers as we can.
  1452.                 gCapParms.wNumVideoRequested = 
  1453.                         gCapParms.fUsingDOSMemory ? 32 : 1000;
  1454.                 // Don't abort on the left mouse anymore!
  1455.                 gCapParms.fAbortLeftMouse = FALSE;
  1456.                 gCapParms.fAbortRightMouse = TRUE;
  1457.                 // If the Driver is Scrncap.drv, the following values are special
  1458.                 // If wChunkGranularity is zero, the granularity will be set to the
  1459.                 // disk sector size.
  1460.                 gCapParms.wChunkGranularity = (gbIsScrncap ? 32 : 0);
  1461.                 // Scrncap requires a callback for the message pump
  1462.                 capSetCallbackOnYield(ghWndCap, 
  1463.                         (gbIsScrncap ? fpYieldCallback : NULL));
  1464.                 // If the user has hit OK, set the new setup info
  1465.                 capCaptureSetSetup(ghWndCap, &gCapParms, sizeof(CAPTUREPARMS)) ;
  1466.             } else {
  1467.                 break;
  1468.             }
  1469.             // if no capture file, get that
  1470.             if (lstrlen(gachCaptureFile) <= 0) {
  1471.                 cmdSetCaptureFile(hWnd);
  1472.                 if (lstrlen(gachCaptureFile) <= 0) {
  1473.                     break;
  1474.                 }
  1475.             }
  1476.             // Capture video sequence
  1477.             fResult = capCaptureSequence(ghWndCap) ;
  1478.             break;
  1479.         case IDM_C_CAPTUREFRAME:
  1480.             // Turn off overlay / preview (gets turned off by frame capture)
  1481.             vidcapSetLive(FALSE);
  1482.             vidcapSetOverlay(FALSE);
  1483.             // Grab a frame
  1484.             fResult = capGrabFrameNoStop(ghWndCap) ;
  1485.             break;
  1486.         case IDM_C_CAPSEL:
  1487.             {
  1488.                 FARPROC fproc;
  1489.                 // if no capture file, get that
  1490.                 if (lstrlen(gachCaptureFile) <= 0) {
  1491.                     cmdSetCaptureFile(hWnd);
  1492.                     if (lstrlen(gachCaptureFile) <= 0) {
  1493.                         break;
  1494.                     }
  1495.                 }
  1496.                 fproc = MakeProcInstance(CapFramesProc, ghInstApp);
  1497.                 DialogBox(ghInstApp, MAKEINTRESOURCE(IDD_CAPFRAMES), hWnd, (DLGPROC) fproc);
  1498.                 FreeProcInstance(fproc);
  1499.             }
  1500.             break;
  1501. #ifdef DEBUG
  1502.         case IDM_C_TEST:
  1503.     nTestCount = 0;
  1504.     // Intentional fall through
  1505.     
  1506.         case IDM_C_TESTAGAIN:
  1507.             // set the defaults we won't bother the user with
  1508.             gCapParms.fMakeUserHitOKToCapture = FALSE;
  1509.             gCapParms.wPercentDropForError = 100;
  1510.             gCapParms.wNumVideoRequested = 
  1511.                     gCapParms.fUsingDOSMemory ? 32 : 1000;
  1512.             // Don't abort on the left mouse anymore!
  1513.             gCapParms.fAbortLeftMouse = FALSE;
  1514.             gCapParms.fAbortRightMouse = TRUE;
  1515.             // If wChunkGranularity is zero, the granularity will be set to the
  1516.             // disk sector size.
  1517.             gCapParms.wChunkGranularity = (gbIsScrncap ? 32 : 0);
  1518.             // If the user has hit OK, set the new setup info
  1519.             capCaptureSetSetup(ghWndCap, &gCapParms, sizeof(CAPTUREPARMS)) ;
  1520.             // if no capture file, get that
  1521.             if (lstrlen(gachCaptureFile) <= 0) {
  1522.                 cmdSetCaptureFile(hWnd);
  1523.                 if (lstrlen(gachCaptureFile) <= 0) {
  1524.                     break;
  1525.                 }
  1526.             }
  1527.     
  1528.     {
  1529. char buf[80];
  1530.                 gCapParms.wNumVideoRequested = 10;
  1531.                 gCapParms.wNumAudioRequested = 5;
  1532. gCapParms.fLimitEnabled = TRUE;
  1533. if (gCapParms.wTimeLimit == 0)
  1534.     gCapParms.wTimeLimit = 5;
  1535. capCaptureSetSetup(ghWndCap, &gCapParms, sizeof(CAPTUREPARMS)) ;
  1536. // Capture video sequence
  1537.                 fResult = capCaptureSequence(ghWndCap) ;
  1538. wsprintf (buf, "TestCount = %d", nTestCount++);
  1539. statusUpdateStatus(ghWndStatus, buf);
  1540. // Hold down the right mouse button to abort
  1541. if (!GetAsyncKeyState(VK_RBUTTON) & 0x0001)
  1542.     PostMessage (hWnd, WM_COMMAND, IDM_C_TESTAGAIN, 0L);
  1543.             }
  1544.             break;
  1545. #endif
  1546.     
  1547. /* --- help --- */
  1548.         case IDM_H_CONTENTS:
  1549.             HelpContents();
  1550.             break;
  1551.         case IDM_H_ABOUT:
  1552.             ShellAbout(
  1553.                 hWnd,
  1554.                 "VidCap",
  1555.                 "Video Capture Tool",
  1556.                 LoadIcon(ghInstApp,  gachIconName)
  1557.             );
  1558.             //DoDialog(hWnd, IDD_HelpAboutBox, AboutProc, 0);
  1559.             break ;
  1560.     }
  1561.     return 0L ;
  1562. }
  1563. /* --- menu help and enable/disable handling ------------------------ */
  1564. // write or clear status line help text when the user brings up or cancels a
  1565. // menu. This depends on there being strings in the string table with
  1566. // the same ID as the corresponding menu item.
  1567. // Help text for the items along the menu bar (File, Edit etc) depends
  1568. // on IDM_FILE, IDM_EDIT being defined with values 100 apart in the same
  1569. // order as their index in the menu
  1570. void
  1571. MenuSelect(HWND hwnd, UINT cmd, UINT flags, HMENU hmenu)
  1572. {
  1573.     if ((LOWORD(flags) == 0xffff) && (hmenu == NULL)) {
  1574.         //menu closing - remove message
  1575.         statusUpdateStatus(ghWndStatus, NULL);
  1576.     } else if ( (flags & (MF_SYSMENU|MF_POPUP)) == (MF_SYSMENU|MF_POPUP)) {
  1577.         // the system menu itself
  1578.         statusUpdateStatus(ghWndStatus, MAKEINTRESOURCE(IDM_SYSMENU));
  1579.     } else if ((flags & MF_POPUP) == 0) {
  1580.         // a menu command item
  1581.         statusUpdateStatus(ghWndStatus, MAKEINTRESOURCE(cmd));
  1582.     } else {
  1583.         //a popup menu - we need to search to find which one.
  1584.         // note that the cmd item in Win16 will now have a
  1585.         // menu handle, whereas in Win32 it has an index.
  1586.         // NOTE: this code assumes that the menu items
  1587.         // are #defined 100 apart in the same order, starting
  1588.         // with IDM_FILE
  1589. #ifdef _WIN32
  1590.         statusUpdateStatus(ghWndStatus, MAKEINTRESOURCE(IDM_FILE + (cmd * 100)));
  1591. #else
  1592.         int i,c;
  1593.         HMENU hmenuMain; 
  1594.         hmenuMain = GetMenu(hWnd);
  1595.         c = GetMenuItemCount(hmenuMain);
  1596.         for(i = 0; i < c; i++) {
  1597.             if (hmenu == GetSubMenu(hmenuMain, i)) {
  1598.                 statusUpdateStatus(MAKEINTRESOURCE(IDM_FILE + (cmd*100)));
  1599.                 return(0);
  1600.             }
  1601.         }
  1602.         statusUpdateStatus(NULL);
  1603. #endif
  1604.     }
  1605. }
  1606. // a popup menu is being selected - enable or disable menu items
  1607. int
  1608. InitMenuPopup(
  1609.     HWND hwnd,
  1610.     HMENU hmenu,
  1611.     int index
  1612. )
  1613. {
  1614.     int i = MF_ENABLED;
  1615.     CAPSTATUS cs;
  1616.     BOOL bUsesPalettes;
  1617.     capGetStatus(ghWndCap, &cs, sizeof(cs));
  1618.     // try to see if the driver uses palettes
  1619.     if ((cs.hPalCurrent != NULL) || (cs.fUsingDefaultPalette)) {
  1620.         bUsesPalettes = TRUE;
  1621.     } else {
  1622.         bUsesPalettes = FALSE;
  1623.     }
  1624.     switch(index) {
  1625.     case 0:         // IDM_FILE
  1626.         if (lstrlen(gachCaptureFile) <= 0) {
  1627.             i = MF_GRAYED;
  1628.         }
  1629.         // save as enabled only if we have a capture file
  1630.         EnableMenuItem(hmenu, IDM_F_SAVEVIDEOAS, i);
  1631.         // edit video possible only if we have a capture file AND we've
  1632.         // captured something
  1633.         EnableMenuItem(hmenu, IDM_F_EDITVIDEO,
  1634.             (cs.dwCurrentVideoFrame > 0) ? i : MF_GRAYED);
  1635.         // allow save palette if there is one
  1636.         EnableMenuItem(hmenu, IDM_F_SAVEPALETTE,
  1637.             (cs.hPalCurrent != NULL) ? MF_ENABLED:MF_GRAYED);
  1638.         // allow load palette if the driver uses palettes
  1639.         EnableMenuItem(hmenu, IDM_F_LOADPALETTE,
  1640.             bUsesPalettes ? MF_ENABLED : MF_GRAYED);
  1641.         break;
  1642.     case 1:         // IDM_EDIT
  1643.         // paste palettes if driver uses them and there is one pastable
  1644.         EnableMenuItem(hmenu, IDM_E_PASTEPALETTE,
  1645.             (bUsesPalettes && IsClipboardFormatAvailable(CF_PALETTE)) ? MF_ENABLED:MF_GRAYED);
  1646.         break;
  1647.     case 2:         // IDM_OPTIONS
  1648.         EnableMenuItem(hmenu, IDM_O_AUDIOFORMAT,
  1649.             cs.fAudioHardware ? MF_ENABLED : MF_GRAYED);
  1650.         EnableMenuItem(hmenu, IDM_O_OVERLAY,
  1651.             gCapDriverCaps.fHasOverlay ? MF_ENABLED:MF_GRAYED);
  1652.         EnableMenuItem(hmenu, IDM_O_VIDEOFORMAT,
  1653.             gCapDriverCaps.fHasDlgVideoFormat ? MF_ENABLED:MF_GRAYED);
  1654.         EnableMenuItem(hmenu, IDM_O_VIDEODISPLAY,
  1655.             gCapDriverCaps.fHasDlgVideoDisplay ? MF_ENABLED:MF_GRAYED);
  1656.         EnableMenuItem(hmenu, IDM_O_VIDEOSOURCE,
  1657.             gCapDriverCaps.fHasDlgVideoSource ? MF_ENABLED:MF_GRAYED);
  1658.         EnableMenuItem(hmenu, IDM_O_PREVIEW,
  1659.                 gbHaveHardware ? MF_ENABLED:MF_GRAYED);
  1660.     case 3:     // IDM_CAPTURE
  1661.         if (!gbHaveHardware) {
  1662.             i = MF_GRAYED;
  1663.         }
  1664.         EnableMenuItem(hmenu, IDM_C_CAPSEL, i);
  1665.         EnableMenuItem(hmenu, IDM_C_CAPTUREFRAME, i);
  1666.         EnableMenuItem(hmenu, IDM_C_CAPTUREVIDEO, i);
  1667.         EnableMenuItem(hmenu, IDM_C_PALETTE, (gbHaveHardware &&
  1668.             gCapDriverCaps.fDriverSuppliesPalettes) ? MF_ENABLED : MF_GRAYED);
  1669.         break;
  1670.     }
  1671.     return(0);
  1672. }
  1673. //
  1674. // MainWndProc: Application Main Window Procedure
  1675. //
  1676. LONG FAR PASCAL MainWndProc(HWND hWnd, UINT Message, UINT wParam, LONG lParam)
  1677. {
  1678. ////////////////////////////////////////////////////////////////////////
  1679. //  hWnd:      Application main window handle
  1680. //  Message:   Next message to be processed
  1681. //  wParam:    WORD param for the message
  1682. //  lParam:    LONG param for the message
  1683. ////////////////////////////////////////////////////////////////////////
  1684.     switch (Message) {
  1685.         static BOOL fMinimized;
  1686.         case WM_SYSCOMMAND:
  1687.     if ((wParam & 0xfff0) == SC_MAXIMIZE)
  1688.      fMinimized = FALSE;
  1689.     else if ((wParam & 0xfff0) == SC_RESTORE)
  1690.      fMinimized = FALSE;
  1691.     else if ((wParam & 0xfff0) == SC_MINIMIZE)
  1692.      fMinimized = TRUE;
  1693.     return DefWindowProc(hWnd, Message, wParam, lParam);
  1694.     break;
  1695.         case WM_COMMAND:
  1696.             MenuProc(hWnd, wParam, lParam) ;
  1697.             break ;
  1698.         case WM_CREATE:
  1699.             HelpInit(ghInstApp, "vidcap.hlp", hWnd);
  1700.             break;
  1701.         case WM_NCHITTEST:
  1702.         {
  1703.             DWORD dw;
  1704.             dw = DefWindowProc(hWnd, Message, wParam, lParam);
  1705.             // Don't allow border resize if autosizing
  1706.             if (gbAutoSizeFrame) {
  1707.                 if (dw >= HTSIZEFIRST && dw <= HTSIZELAST)
  1708.                     dw = HTCAPTION;
  1709.             }
  1710.             return dw;
  1711.                 
  1712.         }
  1713.             break;
  1714.         case WM_GETMINMAXINFO:
  1715.             // Don't allow manual sizing if window locked to the capture size
  1716.             if (gbHaveHardware && gbAutoSizeFrame && !gbInLayout) {
  1717.                 RECT rW;
  1718.                 LPMINMAXINFO lpMMI = (LPMINMAXINFO) lParam;
  1719.                 GetWindowRect (hWnd, &rW);
  1720.                 lpMMI->ptMinTrackSize.x = rW.right - rW.left;
  1721.                 lpMMI->ptMinTrackSize.y = rW.bottom - rW.top;
  1722.                 lpMMI->ptMaxTrackSize = lpMMI->ptMinTrackSize;
  1723.             }
  1724.             break;
  1725.         case WM_MOVE:
  1726.     if (!fMinimized) {
  1727.      vidcapLayout (hWnd);
  1728.     }
  1729.     break;
  1730.         case WM_SIZE:
  1731.     if (!fMinimized) {
  1732.      vidcapLayout (hWnd);
  1733.     }
  1734.     break;
  1735.         case WM_MENUSELECT:
  1736.             {
  1737.                 UINT cmd = GET_WM_MENUSELECT_CMD(wParam, lParam);
  1738.                 UINT flags = GET_WM_MENUSELECT_FLAGS(wParam, lParam);
  1739.                 HMENU hmenu = GET_WM_MENUSELECT_HMENU(wParam, lParam);
  1740.                 MenuSelect(hWnd, cmd, flags, hmenu);
  1741.             }
  1742.             break;
  1743.         case WM_INITMENUPOPUP:
  1744.             {
  1745.                 BOOL bSystem = (BOOL) HIWORD(lParam);
  1746.                 if (!bSystem) {
  1747.                     return InitMenuPopup(hWnd,
  1748.                             (HMENU) wParam, (int) LOWORD(lParam));
  1749.                 } else {
  1750.                     return(DefWindowProc(hWnd, Message, wParam, lParam));
  1751.                 }
  1752.             }
  1753.         case WM_SYSCOLORCHANGE:
  1754.             // we don't use this ourselves, but we should pass
  1755.             // it on to all three children
  1756.             SendMessage(ghWndFrame, Message, wParam, lParam);
  1757.             SendMessage(ghWndToolBar, Message, wParam, lParam);
  1758.             SendMessage(ghWndStatus, Message, wParam, lParam);
  1759.             return (TRUE);
  1760.         case WM_PALETTECHANGED:
  1761.         case WM_QUERYNEWPALETTE:
  1762.             // Pass the buck to Capture window proc
  1763.             return SendMessage(ghWndCap, Message, wParam, lParam) ;
  1764.             break ;
  1765.         case WM_SETFOCUS:
  1766.             // the toolbar is the only part that needs the focus
  1767.             SetFocus(ghWndToolBar);
  1768.             break;
  1769.         case WM_ACTIVATEAPP:
  1770.             if (wParam && ghWndCap) 
  1771.                 capPreviewRate(ghWndCap, 15); // Fast preview when active
  1772.             else
  1773.                 capPreviewRate(ghWndCap, 1000); // Slow preview when inactive
  1774.             break;
  1775.         case WM_NEXTDLGCTL:
  1776.             // if anyone is tabbing about, move the focus to the
  1777.             // toolbar
  1778.             SetFocus(ghWndToolBar);
  1779.             // select the correct button to handle moving off one
  1780.             // end and back on the other end
  1781.             if (lParam == FALSE) {
  1782.                 // are we moving forwards or backwards ?
  1783.                 if (wParam == 0) {
  1784.                     // move to next - so select first button
  1785.                     toolbarSetFocus(ghWndToolBar, TB_FIRST);
  1786.                 } else {
  1787.                     // move to previous - so select last
  1788.                     toolbarSetFocus(ghWndToolBar, TB_LAST);
  1789.                 }
  1790.             }
  1791.             break;
  1792.         case WM_PAINT:
  1793.         {
  1794.             HDC           hDC ;
  1795.             PAINTSTRUCT   ps ;
  1796.             hDC = BeginPaint(hWnd, &ps) ;
  1797.             // Included in case the background is not a pure color
  1798.             SetBkMode(hDC, TRANSPARENT) ;
  1799.             EndPaint(hWnd, &ps) ;
  1800.             break ;
  1801.         }
  1802.         case WM_CLOSE:
  1803.             // Disable and free all the callbacks 
  1804.             capSetCallbackOnError(ghWndCap, NULL) ;
  1805. if (fpErrorCallback) {
  1806.              FreeProcInstance(fpErrorCallback) ;
  1807. fpErrorCallback = NULL;
  1808. }
  1809.             capSetCallbackOnStatus(ghWndCap, NULL) ;
  1810. if (fpStatusCallback) {
  1811.              FreeProcInstance(fpStatusCallback) ;
  1812. fpStatusCallback = NULL;
  1813. }
  1814.             capSetCallbackOnYield(ghWndCap, NULL) ;
  1815. if (fpYieldCallback) {
  1816.              FreeProcInstance(fpYieldCallback) ;
  1817. fpYieldCallback = NULL;
  1818. }
  1819.             // Disconnect the current capture driver
  1820.             capDriverDisconnect (ghWndCap);
  1821.             // Destroy child windows, modeless dialogs, then this window...
  1822.             // DestroyWindow(ghWndCap) ;
  1823.             DestroyWindow(hWnd) ;
  1824.             break ;
  1825.         case WM_DESTROY:
  1826.             {
  1827.                 // remember window size and position
  1828.                 // - this will be written to the profile
  1829.                 WINDOWPLACEMENT wp;
  1830.                 wp.length = sizeof (WINDOWPLACEMENT);
  1831.                 GetWindowPlacement(hWnd, &wp);
  1832.                 gWinShow = wp.showCmd;
  1833.                 gWinX = wp.rcNormalPosition.left;
  1834.                 gWinY = wp.rcNormalPosition.top;
  1835.                 gWinCX = RECTWIDTH(wp.rcNormalPosition);
  1836.                 gWinCY = RECTHEIGHT(wp.rcNormalPosition);
  1837.                 // write defaults out to the registry
  1838.                 vidcapWriteProfile();
  1839.                 vidcapWriteSettingsProfile();
  1840.                 HelpShutdown();
  1841.             }
  1842.             PostQuitMessage(0) ;
  1843.             break ;
  1844.         default:
  1845.             return DefWindowProc(hWnd, Message, wParam, lParam) ;
  1846.     }
  1847.     return 0L;
  1848. }   // End of MainWndProc