CAPTEST.C
/************************************************************************** 
 * 
 *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
 *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR 
 *  PURPOSE. 
 * 
 *  Copyright 1992 - 1998 Microsoft Corporation.  All Rights Reserved. 
 * 
 **************************************************************************/ 
/**************************************************************************** 
 * 
 *   captest.c: Source Code for the CapTest Sample Program 
 * 
 *   Microsoft Video for Windows Capture Class Sample Program 
 * 
 ***************************************************************************/ 
 
 
#define ENABLE_ERROR_CALLBACK           1 
#define ENABLE_STATUS_CALLBACK          1 
#define ENABLE_VIDEOFRAME_CALLBACKS     0 
 
#define INC_OLE2 
#include <windows.h> 
#include <windowsx.h> 
#include <commdlg.h> 
#include <vfw.h> 
#include <mmreg.h> 
#include <io.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <memory.h> 
#include <dos.h> 
 
#include "captest.h" 
 
// 
// Global Variables 
// 
TCHAR           gachAppName[]  = TEXT("CapTestApp") ; 
TCHAR           gachIconName[] = TEXT("CapTestIcon") ; 
TCHAR           gachMenuName[] = TEXT("CapTestMenu") ; 
TCHAR           gachMCIDeviceName[21] = TEXT("VideoDisc") ;  // default MCI device 
TCHAR           gachString[128] ; 
TCHAR           gachBuffer[200] ; 
 
HINSTANCE      ghInstApp ; 
HWND           ghWndMain ; 
HWND           ghWndCap ; 
HANDLE         ghAccel ; 
WORD           gwDeviceIndex ; 
WORD           gwPalFrames = DEF_PALNUMFRAMES ; 
WORD           gwPalColors = DEF_PALNUMCOLORS ; 
WORD           gwCapFileSize ; 
DWORD          gdwFrameNum ; 
DWORD          gdwVideoNum ; 
 
CAPSTATUS      gCapStatus ; 
CAPDRIVERCAPS  gCapDriverCaps ; 
CAPTUREPARMS   gCapParms ; 
 
LPWAVEFORMATEX glpwfex ; 
 
// MakeProcInstance is only required for 16-bit apps 
#ifndef WIN32 
 FARPROC        fpErrorCallback; 
 FARPROC        fpStatusCallback; 
 FARPROC        fpFrameCallback; 
 FARPROC        fpVideoCallback; 
#endif 
 
// Function prototypes 
// 
LONG FAR PASCAL MainWndProc(HWND, UINT, UINT, LONG) ; 
LRESULT FNWCALLBACK ErrorCallbackProc(HWND, int, LPTSTR) ; 
LRESULT FNWCALLBACK StatusCallbackProc(HWND, int, LPTSTR) ; 
LRESULT FNWCALLBACK FrameCallbackProc(HWND, LPVIDEOHDR) ; 
LRESULT FNWCALLBACK VideoCallbackProc(HWND, LPVIDEOHDR) ; 
 
// 
// WinMain: Application Entry Point Function 
// 
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) 
{ 
/////////////////////////////////////////////////////////////////////// 
//  hInstance:      handle for this instance 
//  hPrevInstance:  handle for possible previous instances 
//  lpszCmdLine:    long pointer to exec command line 
//  nCmdShow:       Show code for main window display 
/////////////////////////////////////////////////////////////////////// 
 
    MSG          msg ; 
    WNDCLASS     wc ; 
 
    ghInstApp = hInstance ; 
    if (! hPrevInstance) { 
        // If it's the first instance, register the window class 
        wc.lpszClassName = gachAppName ; 
        wc.hInstance     = hInstance ; 
        wc.lpfnWndProc   = MainWndProc ; 
        wc.hCursor       = LoadCursor(NULL, IDC_ARROW) ; 
        wc.hIcon         = LoadIcon(hInstance, gachIconName) ; 
        wc.lpszMenuName  = gachMenuName ; 
        wc.hbrBackground = GetStockObject(WHITE_BRUSH) ; 
        wc.style         = CS_HREDRAW | CS_VREDRAW ; 
        wc.cbClsExtra    = 0 ; 
        wc.cbWndExtra    = 0 ; 
 
        if (! RegisterClass(&wc)) { 
            LoadString(ghInstApp, IDS_ERR_REGISTER_CLASS, gachString, sizeof(gachString)/sizeof(TCHAR)) ; 
            MessageBox(NULL, gachString, NULL, 
#ifdef BIDI 
                MB_RTL_READING | 
#endif 
 
            MB_ICONEXCLAMATION) ; 
            return 0 ; 
        } 
    } 
 
    // Create Application's Main window 
    ghWndMain = 
#ifdef BIDI 
 
// 
// unfortunately you can't just #ifdef the CreateWindow line and leave 
// the parameters common: on Win32, CreateWindow is a macro and does not 
// expand correctly if you ifdef only the 'CreateWindow(' line. 
// 
        CreateWindowEx(WS_EX_BIDI_SCROLL |  WS_EX_BIDI_MENU |WS_EX_BIDI_NOICON, 
                             gachAppName, 
                             TEXT("Capture Test App"), 
                             WS_CAPTION      | 
                             WS_SYSMENU      | 
                             WS_MINIMIZEBOX  | 
                             WS_MAXIMIZEBOX  | 
                             WS_THICKFRAME   | 
                             WS_CLIPCHILDREN | 
                             WS_OVERLAPPED, 
                             CW_USEDEFAULT, 0, 
                             320, 240, 
                             NULL, 
                             NULL, 
                             ghInstApp, 
                             NULL) ; 
#else 
        CreateWindow ( 
                             gachAppName, 
                             TEXT("Capture Test App"), 
                             WS_CAPTION      | 
                             WS_SYSMENU      | 
                             WS_MINIMIZEBOX  | 
                             WS_MAXIMIZEBOX  | 
                             WS_THICKFRAME   | 
                             WS_CLIPCHILDREN | 
                             WS_OVERLAPPED, 
                             CW_USEDEFAULT, 0, 
                             320, 240, 
                             NULL, 
                             NULL, 
                             ghInstApp, 
                             NULL) ; 
#endif 
 
    if (ghWndMain == NULL) { 
        LoadString(ghInstApp, IDS_ERR_CREATE_WINDOW, gachString, sizeof(gachString)/sizeof(TCHAR)) ; 
        MessageBox(NULL, gachString, NULL, 
#ifdef BIDI 
                MB_RTL_READING | 
#endif 
 
        MB_ICONEXCLAMATION | MB_OK) ; 
        return IDS_ERR_CREATE_WINDOW ; 
    } 
 
    ShowWindow(ghWndMain, nCmdShow) ; 
    UpdateWindow(ghWndMain) ; 
    ghAccel = LoadAccelerators(ghInstApp, gachAppName) ; 
 
    // All set; get and process messages 
    while (GetMessage(&msg, NULL, 0, 0)) { 
        if (! TranslateAccelerator(ghWndMain, ghAccel, &msg)) { 
            TranslateMessage(&msg) ; 
            DispatchMessage(&msg) ; 
        } 
    } 
 
    return msg.wParam ; 
}  // End of WinMain 
 
 
// 
// ErrorCallbackProc: Error Callback Function 
// 
LRESULT FNWCALLBACK ErrorCallbackProc(HWND hWnd, int nErrID, LPTSTR lpErrorText) 
{ 
//////////////////////////////////////////////////////////////////////// 
//  hWnd:          Application main window handle 
//  nErrID:        Error code for the encountered error 
//  lpErrorText:   Error text string for the encountered error 
//////////////////////////////////////////////////////////////////////// 
 
    if (!ghWndMain) 
        return FALSE; 
 
    if (nErrID == 0)            // Starting a new major function 
        return TRUE;            // Clear out old errors... 
 
    // Show the error ID and text 
    wsprintf(gachBuffer, TEXT("Error# %d"), nErrID) ; 
 
    MessageBox(hWnd, lpErrorText, gachBuffer, 
#ifdef BIDI 
                MB_RTL_READING | 
#endif 
                MB_OK | MB_ICONEXCLAMATION) ; 
 
    return (LRESULT) TRUE ; 
} 
 
 
// 
// StatusCallbackProc: Status Callback Function 
// 
LRESULT FNWCALLBACK StatusCallbackProc(HWND hWnd, int nID, LPTSTR lpStatusText) 
{ 
//////////////////////////////////////////////////////////////////////// 
//  hWnd:           Application main window handle 
//  nID:            Status code for the current status 
//  lpStatusText:   Status text string for the current status 
//////////////////////////////////////////////////////////////////////// 
 
    if (!ghWndMain) 
        return FALSE; 
 
    if (nID == 0) {              // Zero means clear old status messages 
        SetWindowText(ghWndMain, (LPTSTR) gachAppName) ; 
        return (LRESULT) TRUE ; 
    } 
 
    // Show the status ID and status text... 
    wsprintf(gachBuffer, TEXT("Status# %d: %s"), nID, lpStatusText) ; 
 
        SetWindowText(ghWndMain, (LPTSTR)gachBuffer) ; 
 
    return (LRESULT) TRUE ; 
} 
 
 
// 
// FrameCallbackProc: Frame Callback Function 
// Called whenever a new frame is captured but not streaming 
// 
LRESULT FNWCALLBACK FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr) 
{ 
//////////////////////////////////////////////////////////////////////// 
//  hWnd:       Application main window handle 
//  lpVHdr:     long pointer to VideoHdr struct containing captured 
//              frame information 
//////////////////////////////////////////////////////////////////////// 
 
    if (!ghWndMain) 
        return FALSE; 
 
    wsprintf(gachBuffer, TEXT("Preview frame# %ld "), gdwFrameNum++) ; 
 
    SetWindowText(ghWndMain, (LPTSTR)gachBuffer) ; 
    return (LRESULT) TRUE ; 
} 
 
 
// 
// VideoCallbackProc: Video Stream Callback Function 
// Called whenever a new frame is captured while streaming 
// 
LRESULT FNWCALLBACK VideoCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr) 
{ 
//////////////////////////////////////////////////////////////////////// 
//  hWnd:       Application main window handle 
//  lpVHdr:     long pointer to VideoHdr struct containing captured 
//              frame information 
//////////////////////////////////////////////////////////////////////// 
 
    gdwVideoNum++;      // Testing:  just count the callbacks 
 
    return (LRESULT) TRUE ; 
} 
 
 
// 
// CenterCaptureWindow: Placess Capture Window at the Center of Main Window 
// 
static void CenterCaptureWindow(HWND hWndM, HWND hWndC) 
{ 
//////////////////////////////////////////////////////////////////////// 
//  hWndM:      Application main window handle 
//  hWndC:      Capture window handle 
//////////////////////////////////////////////////////////////////////// 
 
    RECT       MainRect ; 
    RECT       CapRect ; 
    WORD       wCapXPos ; 
    WORD       wCapYPos ; 
 
    // Get the sizes of main and capture windows and 
    // calculate the location for centering 
    GetClientRect(hWndM, &MainRect) ; 
    GetClientRect(hWndC, &CapRect) ; 
    wCapXPos = max(0, (Width(MainRect) - Width(CapRect)) / 2) ; 
    wCapYPos = max(0, (Height(MainRect) - Height(CapRect)) / 2) ; 
 
    // Position the capture window at the required location 
    MoveWindow(hWndC, wCapXPos, wCapYPos, Width(CapRect), 
               Height(CapRect), TRUE) ; 
} 
 
 
// 
// StartNewVideoChannel: Gets Selected Driver's Caps -- Updates menu, 
//                       Checks Image Size -- Resizes display window, 
//                       Enables Preview (at 15 FPS rate) 
// 
static void StartNewVideoChannel(HWND hWndM, HWND hWndC, WORD wIndex) 
{ 
//////////////////////////////////////////////////////////////////////// 
//  hWndM:      Application main window handle 
//  hWndC:      Capture window handle 
//  wIndex:     Selected capture driver index 
//////////////////////////////////////////////////////////////////////// 
 
    HMENU       hMenu = GetMenu(hWndM) ; 
 
    // Get capture driver settings and update menu 
    capDriverGetCaps(hWndC, &gCapDriverCaps, sizeof(CAPDRIVERCAPS)) ; 
    EnableMenuItem(hMenu, IDM_O_OVERLAY, MF_BYCOMMAND | 
                gCapDriverCaps.fHasOverlay ? MF_ENABLED : MF_GRAYED) ; 
    EnableMenuItem(hMenu, IDM_O_VIDEOFORMAT, MF_BYCOMMAND | 
                gCapDriverCaps.fHasDlgVideoFormat ? MF_ENABLED : MF_GRAYED) ; 
    EnableMenuItem(hMenu, IDM_O_VIDEOSOURCE, MF_BYCOMMAND | 
                gCapDriverCaps.fHasDlgVideoSource ? MF_ENABLED : MF_GRAYED) ; 
    EnableMenuItem(hMenu, IDM_O_VIDEODISPLAY, MF_BYCOMMAND | 
                gCapDriverCaps.fHasDlgVideoDisplay ? MF_ENABLED : MF_GRAYED) ; 
 
    // Get video format and adjust capture window 
    capGetStatus(hWndC, &gCapStatus, sizeof(CAPSTATUS)) ; 
    SetWindowPos(hWndC, NULL, 0, 0, gCapStatus.uiImageWidth, 
                 gCapStatus.uiImageHeight, SWP_NOZORDER | SWP_NOMOVE) ; 
 
    // Start preview by default 
    capPreviewRate(hWndC, MS_FOR_15FPS) ; 
    capPreview(hWndC, TRUE) ; 
 
    // Put check mark beside appropriate menu options 
    CheckMenuItem(hMenu, wIndex + IDM_O_DRIVERS, MF_BYCOMMAND | MF_CHECKED) ; 
} 
 
 
// 
// MenuProc: Processes All Menu-based Operations 
// 
long FAR PASCAL MenuProc(HWND hWnd, UINT wParam, LONG lParam) 
{ 
//////////////////////////////////////////////////////////////////////// 
//  hWnd:      Application main window handle 
//  hMenu:     Application menu handle 
//  wParam:    Menu option 
//  lParam:    Additional info for any menu option 
//////////////////////////////////////////////////////////////////////// 
 
    OPENFILENAME ofn ; 
    DWORD        dwError ; 
    WORD         wIndex ; 
    BOOL         fResult ; 
    DWORD        dwSize ; 
    TCHAR        achBuffer[_MAX_PATH] ; 
    TCHAR        achFileName[_MAX_PATH] ; 
    TCHAR        *szFileFilter = TEXT("Microsoft AVI\0") 
                                 TEXT("*.avi\0") 
                                 TEXT("All Files\0") 
                                 TEXT("*.*\0") ; 
 
    HMENU hMenu = GetMenu(hWnd) ; 
 
    switch (wParam) { 
        case IDM_F_SETCAPTUREFILE: 
        { 
            LPTSTR p; 
 
            // Get current capture file name and 
            // then try to get the new capture file name 
            dwError = capFileGetCaptureFile(ghWndCap, achFileName, 
                                        sizeof(achFileName)/sizeof(TCHAR)); 
            if (dwError) { 
 
                // Get just the path info 
                // Terminate the full path at the last backslash 
                lstrcpy (achBuffer, achFileName); 
                for (p = achBuffer + lstrlen(achBuffer); p > achBuffer; p--) { 
                    if (*p == '\\') { 
                        *(p+1) = '\0'; 
                        break; 
                    } 
                } 
 
                _fmemset(&ofn, 0, sizeof(OPENFILENAME)) ; 
                ofn.lStructSize = sizeof(OPENFILENAME) ; 
                ofn.hwndOwner = hWnd ; 
                ofn.lpstrFilter = szFileFilter ; 
                ofn.nFilterIndex = 0 ; 
                ofn.lpstrFile = achFileName ; 
                ofn.nMaxFile = sizeof(achFileName)/sizeof(TCHAR) ; 
                ofn.lpstrFileTitle = NULL; 
                ofn.lpstrTitle = TEXT("Set Capture File") ; 
                ofn.nMaxFileTitle = 0 ; 
                ofn.lpstrInitialDir = achBuffer; 
                ofn.Flags = 
#ifdef BIDI 
                OFN_BIDIDIALOG | 
#endif 
                OFN_HIDEREADONLY | 
                OFN_NOREADONLYRETURN | 
                OFN_PATHMUSTEXIST ; 
 
                if (GetOpenFileName(&ofn)) 
                    // If the user has hit OK then set capture file name 
                    capFileSetCaptureFile(ghWndCap, achFileName) ; 
            } 
        } 
        break; 
 
        case IDM_F_SAVEVIDEOAS: 
            // Get the current capture file name and 
            // then get the substitute file name to save video in 
            dwError = capFileGetCaptureFile(ghWndCap, achFileName, sizeof(achFileName)/sizeof(TCHAR)); 
            if (dwError) { 
 
                _fmemset(&ofn, 0, sizeof(OPENFILENAME)) ; 
                ofn.lStructSize = sizeof(OPENFILENAME) ; 
                ofn.hwndOwner = hWnd ; 
                ofn.lpstrFilter = szFileFilter ; 
                ofn.nFilterIndex = 0 ; 
                ofn.lpstrFile = achFileName ; 
                ofn.nMaxFile = sizeof(achFileName)/sizeof(TCHAR) ; 
                ofn.lpstrFileTitle = NULL ; 
                ofn.lpstrTitle = TEXT("Save Video As...") ; 
                ofn.nMaxFileTitle = 0 ; 
                ofn.lpstrInitialDir = NULL ; 
                ofn.Flags = 
#ifdef BIDI 
                OFN_BIDIDIALOG | 
#endif 
                OFN_PATHMUSTEXIST ; 
 
                if (GetSaveFileName(&ofn)) 
                    // If the user has hit OK then set save file name 
                    capFileSaveAs(ghWndCap, achFileName) ; 
            } 
            break; 
 
        case IDM_F_ALLOCATESPACE: 
            if (DialogBox(ghInstApp, MAKEINTRESOURCE(IDD_AllocCapFileSpace), 
                          hWnd, AllocCapFileProc)) 
                // If user has hit OK then alloc requested capture file space 
                if (! capFileAlloc(ghWndCap, (long) gwCapFileSize * ONEMEG)) 
                    MessageBox(NULL, TEXT("Can't pre-allocate capture file space"), 
                               TEXT("Error"), 
#ifdef BIDI 
                                MB_RTL_READING | 
#endif 
                                MB_OK | MB_ICONEXCLAMATION) ; 
            break ; 
 
        case IDM_F_EXIT: 
            DestroyWindow(hWnd) ; 
            break; 
 
        case IDM_E_COPY: 
            capEditCopy(ghWndCap) ; 
            break; 
 
        case IDM_E_PASTEPALETTE: 
            capPalettePaste(ghWndCap) ; 
            break; 
 
        case IDM_O_PREVIEW: 
            // Toggle Preview 
        capGetStatus(ghWndCap, &gCapStatus, sizeof(CAPSTATUS)) ; 
            capPreview(ghWndCap, !gCapStatus.fLiveWindow) ; 
            break; 
 
        case IDM_O_OVERLAY: 
            // Toggle Overlay 
        capGetStatus(ghWndCap, &gCapStatus, sizeof(CAPSTATUS)) ; 
            capOverlay(ghWndCap, !gCapStatus.fOverlayWindow) ; 
            break ; 
 
        case IDM_O_AUDIOFORMAT: 
#ifdef  USE_ACM 
            { 
                ACMFORMATCHOOSE cfmt; 
 
                // Ask the ACM what the largest wave format is..... 
                acmMetrics(NULL, 
                            ACM_METRIC_MAX_SIZE_FORMAT, 
                            &dwSize); 
 
                // Get the current audio format 
                dwSize = max (dwSize, capGetAudioFormatSize (ghWndCap)); 
                glpwfex = (LPWAVEFORMATEX) GlobalAllocPtr(GHND, dwSize) ; 
                capGetAudioFormat(ghWndCap, glpwfex, (WORD)dwSize) ; 
 
                _fmemset (&cfmt, 0, sizeof (ACMFORMATCHOOSE)); 
                cfmt.cbStruct = sizeof (ACMFORMATCHOOSE); 
                cfmt.fdwStyle =  ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT; 
                cfmt.fdwEnum =   ACM_FORMATENUMF_HARDWARE | 
                                 ACM_FORMATENUMF_INPUT; 
                cfmt.hwndOwner = hWnd; 
                cfmt.pwfx =     glpwfex; 
                cfmt.cbwfx =    dwSize; 
                if (!acmFormatChoose(&cfmt)) 
                    capSetAudioFormat(ghWndCap, glpwfex, (WORD)dwSize) ; 
 
                GlobalFreePtr(glpwfex) ; 
            } 
#else 
            // If not using ACM, remove the reference in the link line 
            // of makefile. 
 
            // Get current audio format and then find required format 
            dwSize = capGetAudioFormatSize (ghWndCap); 
            if(!dwSize) break; 
            glpwfex = (LPWAVEFORMATEX) GlobalAllocPtr(GHND, dwSize) ; 
            capGetAudioFormat(ghWndCap, glpwfex, (WORD)dwSize) ; 
 
            if (DialogBox(ghInstApp, MAKEINTRESOURCE(IDD_AudioFormat), hWnd, AudioFormatProc)) 
                capSetAudioFormat(ghWndCap, glpwfex, (WORD)dwSize);  // If the user has hit OK, set the new audio format 
 
            GlobalFreePtr(glpwfex) ; 
#endif 
            break ; 
 
        case IDM_O_VIDEOFORMAT: 
            if (gCapDriverCaps.fHasDlgVideoFormat) { 
                // Only if the driver has a "Video Format" dialog box 
                if (capDlgVideoFormat(ghWndCap)) {  // If successful, 
                    // Get the new image dimension and center capture window 
                    capGetStatus(ghWndCap, &gCapStatus, sizeof(CAPSTATUS)) ; 
                    SetWindowPos(ghWndCap, NULL, 0, 0, gCapStatus.uiImageWidth, 
                        gCapStatus.uiImageHeight, SWP_NOZORDER | SWP_NOMOVE) ; 
                    CenterCaptureWindow(hWnd, ghWndCap) ; 
                } 
            } 
            break; 
 
        case IDM_O_VIDEOSOURCE: 
            if (gCapDriverCaps.fHasDlgVideoSource) { 
                // Only if the driver has a "Video Source" dialog box 
                capDlgVideoSource(ghWndCap) ; 
            } 
            break ; 
 
        case IDM_O_VIDEODISPLAY: 
            if (gCapDriverCaps.fHasDlgVideoDisplay) { 
                // Only if the driver has a "Video Display" dialog box 
                capDlgVideoDisplay(ghWndCap) ; 
            } 
            break ; 
 
        case IDM_O_PALETTE: 
            if (DialogBox(ghInstApp, MAKEINTRESOURCE(IDD_MakePalette), hWnd, MakePaletteProc)) 
                // If the user has hit OK, capture palette with the 
                // specified number of colors and frames 
                capPaletteAuto(ghWndCap, gwPalFrames, gwPalColors) ; 
            break; 
 
        case IDM_C_CAPTUREVIDEO: 
            gdwVideoNum = 0 ;  // Start counting video frames 
            // Capture video sequence 
            fResult = capCaptureSequence(ghWndCap) ; 
            break; 
 
        case IDM_C_CAPTUREFRAME: 
            gdwFrameNum = 0 ;  // Start counting single frames 
            // Turn off overlay / preview (gets turned off by frame capture) 
    capPreview(ghWndCap, FALSE); 
    capOverlay(ghWndCap, FALSE); 
 
            // Grab a frame 
            fResult = capGrabFrameNoStop(ghWndCap) ; 
            break; 
 
        case IDM_C_CAPTURESETTINGS: 
            // Get the current setup for video capture 
            capCaptureGetSetup(ghWndCap, &gCapParms, sizeof(CAPTUREPARMS)) ; 
 
            // Invoke a Dlg box to setup all the params 
            if (DialogBox(ghInstApp, MAKEINTRESOURCE(IDD_CapSetUp), hWnd, CapSetUpProc)) 
                // If the user has hit OK, set the new setup info 
                capCaptureSetSetup(ghWndCap, &gCapParms, sizeof(CAPTUREPARMS)) ; 
            break; 
 
        case IDM_O_CHOOSECOMPRESSOR: 
            capDlgVideoCompression(ghWndCap); 
            break; 
 
        case IDM_H_ABOUT: 
            DialogBox(ghInstApp, MAKEINTRESOURCE(IDD_HelpAboutBox), hWnd, AboutProc) ; 
            break ; 
 
        default: 
            // There is a chance, a driver change has been requested 
            if ( IsDriverIndex(wParam) ) { 
                // If it's a valid driver index... 
                if (wParam - IDM_O_DRIVERS != gwDeviceIndex) { 
                    // and a different one too then we need to do the rest 
 
                    // Turn off preview/overlay, uncheck current driver option 
                    capPreview(ghWndCap, FALSE) ; 
                    capOverlay(ghWndCap, FALSE) ; 
                    CheckMenuItem(GetMenu(hWnd), gwDeviceIndex + IDM_O_DRIVERS, 
                                  MF_BYCOMMAND | MF_UNCHECKED) ; 
 
                    // Connect to requested driver 
                    if ( capDriverConnect(ghWndCap, (wIndex = (WORD) (wParam - IDM_O_DRIVERS))) ) { 
                        // Connect worked fine -- update menu, start new driver... 
                        CheckMenuItem(GetMenu(hWnd), wParam, MF_BYCOMMAND | MF_CHECKED) ; 
                        gwDeviceIndex = (WORD) (wParam - IDM_O_DRIVERS) ; 
                        StartNewVideoChannel(hWnd, ghWndCap, gwDeviceIndex) ; 
                        CenterCaptureWindow(hWnd, ghWndCap) ; 
                    } 
                    else { 
                        // if connect failed, re-connect back to previous driver 
                        if (! capDriverConnect(ghWndCap, gwDeviceIndex)) { 
                            MessageBox(hWnd, TEXT("Now can't connect back to previous driver !!"), 
                                       TEXT("Error"), 
#ifdef BIDI 
                            MB_RTL_READING | 
#endif 
 
                            MB_OK | MB_ICONSTOP) ; 
                            return -1L ; 
                        } 
                        else 
                            // Re-start previous driver as it was before 
                            StartNewVideoChannel(hWnd, ghWndCap, gwDeviceIndex) ; 
                            CenterCaptureWindow(hWnd, ghWndCap) ; 
                    } 
                }   // end of if ( != gwDeviceIndex) 
            }   // end of if (IsDriverIndex()) 
            else { 
                wsprintf(achBuffer, TEXT("How could you specify this (%u) Driver Index ?"), 
                         wParam - IDM_O_DRIVERS) ; 
                MessageBox(hWnd, achBuffer, TEXT("Oops!!"), 
#ifdef BIDI 
                MB_RTL_READING | 
#endif 
                MB_OK | MB_ICONEXCLAMATION) ; 
            } 
 
            break ; 
    } 
 
    return 0L ; 
} 
 
 
// 
// MainWndProc: Application Main Window Procedure 
// 
LONG FAR PASCAL MainWndProc(HWND hWnd, UINT Message, UINT wParam, LONG lParam) 
{ 
//////////////////////////////////////////////////////////////////////// 
//  hWnd:      Application main window handle 
//  Message:   Next message to be processed 
//  wParam:    WORD param for the message 
//  lParam:    LONG param for the message 
//////////////////////////////////////////////////////////////////////// 
 
    switch (Message) { 
        case WM_COMMAND: 
            MenuProc(hWnd, wParam, lParam) ; 
            break ; 
 
        case WM_CREATE: 
        { 
            TCHAR    achDeviceName[80] ; 
            TCHAR    achDeviceVersion[100] ; 
            TCHAR    achBuffer[100] ; 
            WORD    wDriverCount = 0 ; 
            WORD    wIndex ; 
            DWORD   dwError ; 
            HMENU   hMenu ; 
 
            // First create the capture window 
            ghWndCap = capCreateCaptureWindow((LPTSTR)TEXT("Capture Window"), 
                                              WS_CHILD | WS_VISIBLE, 
                                              0, 0, 160, 120, 
                                              (HWND) hWnd, (int) 0) ; 
 
            hMenu = GetSubMenu(GetMenu(hWnd), 2) ;  // 2 for "Option" 
 
#if ENABLE_ERROR_CALLBACK 
  #ifdef WIN32 
            // Register the status and error callbacks before driver connect 
            capSetCallbackOnError(ghWndCap, ErrorCallbackProc) ; 
  #else 
            fpErrorCallback = MakeProcInstance((FARPROC)ErrorCallbackProc, ghInstApp) ; 
            capSetCallbackOnError(ghWndCap, fpErrorCallback) ; 
  #endif 
#endif 
 
#if ENABLE_STATUS_CALLBACK 
  #ifdef WIN32 
            capSetCallbackOnStatus(ghWndCap, StatusCallbackProc) ; 
  #else 
            fpStatusCallback = MakeProcInstance((FARPROC)StatusCallbackProc, ghInstApp) ; 
            capSetCallbackOnStatus(ghWndCap, fpStatusCallback) ; 
  #endif 
#endif 
 
#if ENABLE_VIDEOFRAME_CALLBACKS 
  #ifdef WIN32 
            capSetCallbackOnVideoStream(ghWndCap, VideoCallbackProc) ; 
            capSetCallbackOnFrame(ghWndCap, FrameCallbackProc) ; 
  #else 
            fpVideoCallback = MakeProcInstance((FARPROC)VideoCallbackProc, ghInstApp) ; 
            capSetCallbackOnVideoStream(ghWndCap, fpVideoCallback) ; 
 
            fpFrameCallback = MakeProcInstance((FARPROC)FrameCallbackProc, ghInstApp) ; 
            capSetCallbackOnFrame(ghWndCap, fpFrameCallback) ; 
  #endif 
#endif 
            // Try to connect one of the MSVIDEO drivers 
            for (wIndex = 0 ; wIndex < MAXVIDDRIVERS ; wIndex++) { 
                if (capGetDriverDescription(wIndex, 
                           (LPTSTR)achDeviceName, sizeof(achDeviceName)/ sizeof(TCHAR), 
                           (LPTSTR)achDeviceVersion, sizeof(achDeviceVersion)/sizeof(TCHAR))) { 
 
                    // There is such a driver in the "system.ini" file. 
                    // Append driver name to "Options" list in menu 
                    wsprintf(achBuffer, TEXT("&%d %s"), wIndex, (LPTSTR)achDeviceName) ; 
                    AppendMenu(hMenu, MF_ENABLED, IDM_O_DRIVERS+wIndex, achBuffer) ; 
 
                    if (wDriverCount++ == 0) { 
                        // Only if no other driver is already connected 
                        dwError = capDriverConnect(ghWndCap, wIndex); 
                        if (dwError) { 
                            CheckMenuItem(GetMenu(hWnd), IDM_O_DRIVERS+wIndex, MF_BYCOMMAND | MF_CHECKED) ; 
                            gwDeviceIndex = wIndex ; 
                        } 
                    } 
                } // end of if (capGetDriverDesc..()) 
            } 
 
            // Now refresh menu, position capture window, start driver etc 
            DrawMenuBar(hWnd) ; 
            CenterCaptureWindow(hWnd, ghWndCap) ; 
            StartNewVideoChannel(hWnd, ghWndCap, gwDeviceIndex) ; 
 
            break ; 
        } 
 
        case WM_MOVE: 
        case WM_SIZE: 
            CenterCaptureWindow(hWnd, ghWndCap) ; 
            break ; 
 
        case WM_PALETTECHANGED: 
        case WM_QUERYNEWPALETTE: 
            // Pass the buck to Capture window proc 
            PostMessage(ghWndCap, Message, wParam, lParam) ; 
            break ; 
 
        case WM_INITMENU: 
        { 
            BOOL          fResult ; 
 
            // Initially check if "Options.PastePalette" should be enabled 
            fResult = IsClipboardFormatAvailable(CF_PALETTE) ? 
                      MF_ENABLED : MF_GRAYED ; 
            EnableMenuItem((HMENU) wParam, IDM_E_PASTEPALETTE, fResult) ; 
 
    // Check/Uncheck Preview and Overlay 
        capGetStatus(ghWndCap, &gCapStatus, sizeof(CAPSTATUS)) ; 
        CheckMenuItem((HMENU)wParam, IDM_O_PREVIEW, gCapStatus.fLiveWindow 
? MF_CHECKED : MF_UNCHECKED); 
CheckMenuItem((HMENU)wParam, IDM_O_OVERLAY,gCapStatus.fOverlayWindow 
? MF_CHECKED : MF_UNCHECKED); 
        } 
 
        case WM_PAINT: 
        { 
            HDC           hDC ; 
            PAINTSTRUCT   ps ; 
 
            hDC = BeginPaint(hWnd, &ps) ; 
 
            // Included in case the background is not a pure color 
            SetBkMode(hDC, TRANSPARENT) ; 
 
            EndPaint(hWnd, &ps) ; 
            break ; 
        } 
 
        case WM_CLOSE: 
            // Disable and free all the callbacks 
#if ENABLE_ERROR_CALLBACK 
            capSetCallbackOnError(ghWndCap, NULL) ; 
  #ifndef WIN32 
            FreeProcInstance(fpErrorCallback) ; 
  #endif 
#endif 
 
#if ENABLE_STATUS_CALLBACK 
            capSetCallbackOnStatus(ghWndCap, NULL) ; 
  #ifndef WIN32 
            FreeProcInstance(fpStatusCallback) ; 
  #endif 
#endif 
 
#if ENABLE_VIDEOFRAME_CALLBACKS 
            capSetCallbackOnFrame(ghWndCap, NULL) ; 
            capSetCallbackOnVideoStream(ghWndCap, NULL) ; 
  #ifndef WIN32 
            FreeProcInstance(fpFrameCallback) ; 
            FreeProcInstance(fpVideoCallback) ; 
  #endif 
#endif 
            // Destroy child windows, modeless dialogs, then this window... 
 
            DestroyWindow(ghWndCap) ; 
            DestroyWindow(hWnd) ; 
            break ; 
 
        case WM_DESTROY: 
            PostQuitMessage(0) ; 
            break ; 
 
        default: 
            return DefWindowProc(hWnd, Message, wParam, lParam) ; 
    } 
 
    return 0L; 
}   // End of MainWndProc