PUZZPROC.C
/**************************************************************************** 
 * 
 *  PUZZPROC.C 
 * 
 *  Modification of standard AVI drawing handler. 
 * 
 ***************************************************************************/ 
/************************************************************************** 
 * 
 *  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. 
 * 
 **************************************************************************/ 
 
#define  STRICT 
#define  INC_OLE2 
#include <windows.h> 
#include <windowsx.h> 
#include <mmsystem.h> 
#include <stdlib.h> 
#include <vfw.h> 
 
#include "puzzproc.h" 
#include "puzzle.h" 
 
#define LOCAL  __stdcall 
#define SZCODE char 
 
static SZCODE szDescription[] = "Microsoft Puzzle Draw handler"; 
static SZCODE szName[]        = "MS Puzzle"; 
 
#define FOURCC_AVIDraw          mmioFOURCC('P','U','Z','Z') 
#define VERSION_AVIDraw         0x00010000      // 1.00 
 
extern PUZZLE   gPuzzle; 
 
/*************************************************************************** 
 ***************************************************************************/ 
 
typedef struct { 
    HDRAWDIB            hdd; 
    HDC                 hdc;            // HDC to draw to 
    int                 xDst;           // destination rectangle 
    int                 yDst; 
    int                 dxDst; 
    int                 dyDst; 
    int                 xSrc;           // source rectangle 
    int                 ySrc; 
    int                 dxSrc; 
    int                 dySrc; 
    LPBYTE              lpBuffer; 
} INSTINFO; 
 
 
/*************************************************************************** 
 ***************************************************************************/ 
 
typedef ICOPEN *                LPICOPEN; 
typedef ICINFO *                LPICINFO; 
typedef ICDRAW *                LPICDRAW; 
typedef ICDRAWSUGGEST *         LPICDRAWSUGGEST; 
typedef ICDRAWBEGIN *           LPICDRAWBEGIN; 
typedef INSTINFO *              LPINSTINFO; 
 
/*************************************************************************** 
 ***************************************************************************/ 
 
// static stuff in this file. 
static LONG LOCAL AVIDrawOpen(LPICOPEN); 
static LONG LOCAL AVIDrawClose(LPINSTINFO); 
static LONG LOCAL AVIDrawGetInfo(LPICINFO, LONG); 
static LONG LOCAL AVIDrawQuery(LPINSTINFO, LPBITMAPINFOHEADER); 
static LONG LOCAL AVIDrawSuggestFormat(LPINSTINFO, LPICDRAWSUGGEST, LONG); 
static LONG LOCAL AVIDrawBegin(LPINSTINFO, LPICDRAWBEGIN, LONG); 
static LONG LOCAL AVIDraw(LPINSTINFO, LPICDRAW, LONG); 
static LONG LOCAL AVIDrawEnd(LPINSTINFO); 
static LONG LOCAL AVIDrawChangePalette(LPINSTINFO, LPBITMAPINFOHEADER); 
 
/*************************************************************************** 
 ***************************************************************************/ 
 
LONG CALLBACK ICAVIDrawProc( 
DWORD id, 
HDRVR hDriver, 
UINT uiMessage, 
LPARAM lParam1, 
LPARAM lParam2) 
{ 
        LPINSTINFO pi = (LPINSTINFO)id; 
 
        switch (uiMessage) { 
 
                case DRV_LOAD: 
                case DRV_FREE: 
                        return 1L; 
 
                //open 
                case DRV_OPEN: 
                        if (lParam2 == 0L) 
                                return 1L; 
                        else 
                                return AVIDrawOpen((LPICOPEN)lParam2); 
 
                //close 
                case DRV_CLOSE: 
                        return AVIDrawClose(pi); 
 
                //Configure and Info messages 
                case DRV_QUERYCONFIGURE:    // configuration from drivers applet 
                        return 0; 
 
                case DRV_CONFIGURE: 
                        return 1; 
 
                case ICM_CONFIGURE: 
                case ICM_ABOUT: 
                        return ICERR_UNSUPPORTED; 
 
                case ICM_GETINFO: 
                        return AVIDrawGetInfo((LPICINFO)lParam1, lParam2); 
 
                //state messages 
                case ICM_GETSTATE: 
                case ICM_SETSTATE: 
                        return 0L; 
 
                //draw messages 
                case ICM_DRAW_QUERY: 
                        return AVIDrawQuery(pi, (LPBITMAPINFOHEADER)lParam1); 
 
                case ICM_DRAW_SUGGESTFORMAT: 
                        return AVIDrawSuggestFormat(pi, (LPICDRAWSUGGEST) lParam1, lParam2); 
 
                case ICM_DRAW_BEGIN: 
                        return AVIDrawBegin(pi, (LPICDRAWBEGIN) lParam1, lParam2); 
 
                case ICM_DRAW_REALIZE: 
                        pi->hdc = (HDC) lParam1; 
                        if (!pi->hdc || !pi->hdd) 
                                break; 
                        return DrawDibRealize(pi->hdd, pi->hdc, (BOOL) lParam2); 
 
                case ICM_DRAW_GET_PALETTE: 
                        if (!pi->hdd) 
                                break; 
                        return (LONG) (UINT) DrawDibGetPalette(pi->hdd); 
 
                case ICM_DRAW: 
                        return AVIDraw(pi, (LPICDRAW)lParam1, lParam2); 
 
                case ICM_DRAW_CHANGEPALETTE: 
                        return AVIDrawChangePalette(pi, (LPBITMAPINFOHEADER) lParam1); 
 
                case ICM_DRAW_END: 
                        return AVIDrawEnd(pi); 
 
                //standard driver messages 
                case DRV_DISABLE: 
                case DRV_ENABLE: 
                        return 1L; 
 
                case DRV_INSTALL: 
                case DRV_REMOVE: 
                        return 1L; 
        } 
        if (uiMessage < DRV_USER) 
                return DefDriverProc(id,hDriver,uiMessage,lParam1,lParam2); 
        else 
                return ICERR_UNSUPPORTED; 
} 
/***************************************************************************** 
 * 
 * AVIDrawOpen() is called from the DRV_OPEN message 
 * 
 ****************************************************************************/ 
 
static LONG LOCAL AVIDrawOpen( 
LPICOPEN icopen) 
{ 
        LPINSTINFO pinst; 
 
        // refuse to open if we are not being opened as a video draw device 
        if (icopen->fccType != streamtypeVIDEO) 
                return 0L; 
 
        if (icopen->dwFlags == ICMODE_COMPRESS) 
                return 0L; 
 
        if (icopen->dwFlags == ICMODE_DECOMPRESS) 
                return 0L; 
 
        pinst = (LPINSTINFO)GlobalAllocPtr(GHND, sizeof(INSTINFO)); 
 
        if (!pinst) { 
                icopen->dwError = ICERR_MEMORY; 
                return 0L; 
        } 
 
        // init structure 
        pinst->hdd = DrawDibOpen(); 
 
        // return success. 
        icopen->dwError = ICERR_OK; 
 
        return (LONG)pinst; 
} 
/***************************************************************************** 
 * 
 * AVIDrawClose() is called on the DRV_CLOSE message. 
 * 
 ****************************************************************************/ 
static LONG LOCAL AVIDrawClose( 
LPINSTINFO pi) 
{ 
        if (pi->hdd) 
                DrawDibClose(pi->hdd); 
 
        if (pi->lpBuffer) 
                GlobalFreePtr(pi->lpBuffer); 
 
        GlobalFreePtr(pi); 
        return 1L; 
} 
/***************************************************************************** 
 * 
 * AVIDrawGetInfo() implements the ICM_GETINFO message 
 * 
 ****************************************************************************/ 
static LONG LOCAL AVIDrawGetInfo( 
LPICINFO icinfo, 
LONG lSize) 
{ 
        if (icinfo == NULL) 
                return sizeof(ICINFO); 
 
        if (lSize < sizeof(ICINFO)) 
                return 0L; 
 
        icinfo->dwSize          = sizeof(ICINFO); 
        icinfo->fccType         = ICTYPE_VIDEO; 
        icinfo->fccHandler      = FOURCC_AVIDraw; 
        icinfo->dwFlags         = VIDCF_DRAW; 
        icinfo->dwVersion       = VERSION_AVIDraw; 
        icinfo->dwVersionICM    = ICVERSION; 
        MultiByteToWideChar(CP_ACP, 0, szDescription, -1, icinfo->szDescription, sizeof(icinfo->szDescription)); 
        MultiByteToWideChar(CP_ACP, 0, szName, -1, icinfo->szDescription, sizeof(icinfo->szDescription)); 
        return sizeof(ICINFO); 
} 
/***************************************************************************** 
 * 
 * AVIDrawQuery() implements ICM_DRAW_QUERY 
 * 
 ****************************************************************************/ 
static LONG LOCAL AVIDrawQuery( 
LPINSTINFO pi, 
LPBITMAPINFOHEADER lpbiIn) 
{ 
        // determine if the input DIB data is in a format we like. 
        if (lpbiIn == NULL) 
                return ICERR_BADFORMAT; 
 
        // determine if the input DIB data is in a format we like. 
        if (lpbiIn->biCompression != BI_RGB) 
                return ICERR_BADFORMAT; 
 
        return ICERR_OK; 
} 
/***************************************************************************** 
 * 
 * AVIDrawSuggestFormat() implements ICM_DRAW_SUGGESTFORMAT 
 * 
 ****************************************************************************/ 
 
static LONG LOCAL AVIDrawSuggestFormat( 
LPINSTINFO pi, 
LPICDRAWSUGGEST lpicd, 
LONG cbicd) 
{ 
        HIC hic; 
        LONG l; 
 
        if (lpicd->lpbiSuggest == NULL) 
                return sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD); 
 
        // Call COMPMAN to get a good format to display data in.... 
        hic = ICGetDisplayFormat(NULL, lpicd->lpbiIn, lpicd->lpbiSuggest, 
                                                0, lpicd->dxDst, lpicd->dyDst); 
 
        if (hic) 
                ICClose(hic); 
 
        l = lpicd->lpbiSuggest->biClrUsed; 
 
        if (lpicd->lpbiSuggest) 
                if (lpicd->lpbiSuggest->biCompression == BI_RLE8) 
                        lpicd->lpbiSuggest->biCompression = BI_RGB; 
 
        // !!! Should check this format here to make sure it's RGB... 
        // !!! If not, we could force it to 8-bit.... 
 
        l = l * sizeof(RGBQUAD); 
        return l + sizeof(BITMAPINFOHEADER); 
} 
 
/***************************************************************************** 
 * 
 * AVIDrawBegin() implements ICM_DRAW_BEGIN 
 * 
 ****************************************************************************/ 
 
static LONG LOCAL AVIDrawBegin( 
LPINSTINFO pi, 
LPICDRAWBEGIN lpicd, 
LONG cbicd) 
{ 
        LONG l = AVIDrawQuery(pi, lpicd->lpbi); 
 
        if ((l != 0) || (lpicd->dwFlags & ICDRAW_QUERY)) 
                return l; 
 
        // Copy over whatever we want to remember 
        pi->hdc = lpicd->hdc; 
        pi->xDst = lpicd->xDst; 
        pi->yDst = lpicd->yDst; 
        pi->dxDst = lpicd->dxDst; 
        pi->dyDst = lpicd->dyDst; 
        pi->xSrc = lpicd->xSrc; 
        pi->ySrc = lpicd->ySrc; 
        pi->dxSrc = lpicd->dxSrc; 
        pi->dySrc = lpicd->dySrc; 
 
        SetStretchBltMode(pi->hdc, COLORONCOLOR); 
 
        if (!DrawDibBegin( 
                        pi->hdd, 
                        pi->hdc, 
                        pi->dxDst, 
                        pi->dyDst, 
                        lpicd->lpbi, 
                        pi->dxSrc, 
                        pi->dySrc, 
                        0)) {  // !!! Flags? 
                return ICERR_UNSUPPORTED; 
        } 
 
        // !!! error check 
 
        // Allocate a buffer for the scrambled picture 
        if (pi->lpBuffer) 
                GlobalFreePtr(pi->lpBuffer); 
 
        pi->lpBuffer = GlobalAllocPtr(GMEM_MOVEABLE, lpicd->lpbi->biSizeImage); 
 
        if (!pi->lpBuffer) 
                return ICERR_MEMORY; 
 
        return ICERR_OK; 
} 
/***************************************************************************** 
 * 
 * AVIDraw() implements ICM_DRAW 
 * 
 ****************************************************************************/ 
 
static LONG LOCAL AVIDraw( 
LPINSTINFO pi, 
LPICDRAW lpicd, 
LONG cbicd) 
{ 
        UINT wFlags = DDF_SAME_HDC; 
 
        if ((lpicd->dwFlags & ICDRAW_NULLFRAME) || lpicd->lpData == NULL) { 
                if (lpicd->dwFlags & ICDRAW_UPDATE) 
                        wFlags |= DDF_UPDATE; 
                else 
                        return ICERR_OK;            // nothing to draw 
        } 
 
        if (lpicd->dwFlags & ICDRAW_PREROLL) 
                wFlags |= DDF_DONTDRAW; 
 
        if (lpicd->dwFlags & ICDRAW_HURRYUP) 
                wFlags |= DDF_HURRYUP; 
 
        // This is the only part that actually has to do with the puzzle: 
        // Mix up the picture into our extra buffer. 
        if (lpicd->lpData) 
                MixPicture(&gPuzzle, lpicd->lpFormat, lpicd->lpData, pi->lpBuffer); 
 
        if (!DrawDibDraw( 
                        pi->hdd, 
                        pi->hdc, 
                        pi->xDst, 
                        pi->yDst, 
                        pi->dxDst, 
                        pi->dyDst, 
                        lpicd->lpFormat, 
                        pi->lpBuffer, 
                        pi->xSrc, 
                        pi->ySrc, 
                        pi->dxSrc, 
                        pi->dySrc, 
                        wFlags)) { 
                if (wFlags & DDF_UPDATE) 
                        return ICERR_CANTUPDATE; 
                else 
                        return ICERR_UNSUPPORTED; 
        } 
 
        return ICERR_OK; 
} 
/***************************************************************************** 
 * 
 * AVIDrawChangePalette() implements ICM_DRAW_CHANGE_PALETTE 
 * 
 ****************************************************************************/ 
 
static LONG LOCAL AVIDrawChangePalette( 
LPINSTINFO pi, 
LPBITMAPINFOHEADER lpbi) 
{ 
        PALETTEENTRY ape[256]; 
        LPRGBQUAD lprgb = (LPRGBQUAD) ((LPBYTE) lpbi + lpbi->biSize); 
        int i; 
 
        for (i = 0; i < (int) lpbi->biClrUsed; i++) { 
                ape[i].peRed = lprgb[i].rgbRed; 
                ape[i].peGreen = lprgb[i].rgbGreen; 
                ape[i].peBlue = lprgb[i].rgbBlue; 
                ape[i].peFlags = 0; 
        } 
 
        DrawDibChangePalette(pi->hdd, 0, (int) lpbi->biClrUsed, (LPPALETTEENTRY)ape); 
        return ICERR_OK; 
} 
/***************************************************************************** 
 * 
 * AVIDrawEnd() implements ICM_DRAW_END 
 * 
 ****************************************************************************/ 
 
static LONG LOCAL AVIDrawEnd( 
LPINSTINFO pi) 
{ 
        // Note: do not call DrawDibEnd here, as we still may be asked to 
        // update our current display, and calling DrawDibEnd would wipe 
        // that out. 
 
        return ICERR_OK; 
}