/******************************Module*Header*******************************\
* Module Name: mfedit.c
*
* Main module for the Enhanced Metafile Editor
*       contains everything
*
* Created: 28-May-1992 14:24:00
* Author: Petrus Wong
*
* Copyright (c) 1992 Microsoft Corporation
*
* The Enhanced Metafile Editor serves to demonstrate the enhanced metafile
* APIs in Windows NT.
*
* The Editor provides the following functions:
*       1.  Playback and recording of GDI calls
*       2.  Embedding bitmap and enhanced metafile into another enhanced
*           metafile with transformation
*       3.  Hit-testing against enhanced metafile records
*       4.  Random access playback
*       5.  Playback metafile records one-by-one
*       6.  Selective recording of existing enhanced metafile records into
*           a new enhanced metafile
*       7.  drawing with pen, text, bezier, line, ellipse, rectangle and
*           embedding bitmap and enhanced metafile tools
*
* Dependencies:
*
*   metadef.h   - contains definition for enhanced metafile records
*
\**************************************************************************/
#include <stdlib.h>
#include "mfedit.h"
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <commdlg.h>
#include <shellapi.h>
#include <math.h>


#if 0
//
// TEST!!!
//
HBITMAP hbmp;


typedef struct tagLOGPAL {
    WORD        palVersion;
    WORD        palNumEntries;
    PALETTEENTRY        palPalEntry[48];
} LOGPAL;

#define exp 17		// explicit entries on end
#define pb 6		// palette base

HPALETTE hPal, hOldPal;
LOGPAL LogPal =
{
	0x300, pb+16+9+exp,
	{
#if pb
           { 0,    0,    0,    PC_RESERVED  },
           { 0,    0,    0,    PC_RESERVED  },
           { 0,    0,    0,    PC_RESERVED  },
           { 0,    0,    0,    PC_RESERVED  },
           { 0,    0,    0,    PC_RESERVED  },
           { 0,    0,    0,    PC_RESERVED  },
#endif
           { 0,    0,    0,    PC_RESERVED  }, // black
           { 0,    0,    255,  PC_RESERVED  }, // blue
           { 255,  0,    0,    PC_RESERVED  }, // red
           { 0,    255,  0,    PC_RESERVED  }, // green
           { 255,  0,    255,  PC_RESERVED  }, // magenta
           { 0,    255,  255,  PC_RESERVED  }, // cyan
           { 255,  255,  0,    PC_RESERVED  }, // yellow
           { 192,  192,  192,  PC_RESERVED  }, // white
           { 96,   96,   96,   PC_RESERVED  }, // dark grey
           { 0,    0,    185,  PC_RESERVED  }, // blue
           { 185,  0,    0,    PC_RESERVED  }, // red
           { 0,    185,  0,    PC_RESERVED  }, // green
           { 185,  0,    185,  PC_RESERVED  }, // magenta
           { 0,    185,  185,  PC_RESERVED  }, // cyan
           { 185,  185,  0,    PC_RESERVED  }, // yellow
           { 255,  255,  255,  PC_RESERVED  }, // white
           { 0,    0,    0,    PC_RESERVED  },
           { 0,    0,    0,    PC_RESERVED  },
           { 0,    0,    0,    PC_RESERVED  },
           { 0,    0,    0,    PC_RESERVED  },
           { 0,    0,    0,    PC_RESERVED  },
           { 0,    0,    0,    PC_RESERVED  },
           { 0,    0,    0,    PC_RESERVED  },
           { 0,    0,    0,    PC_RESERVED  },
           { 0,    0,    0,    PC_RESERVED  },
           { 0,    0,    0,    PC_EXPLICIT  }, // physical palette index 0 (Windows black)
           { 1,    0,    0,    PC_EXPLICIT  }, // physical palette index 1
           { 2,    0,    0,    PC_EXPLICIT  }, // physical palette index 2
           { 3,    0,    0,    PC_EXPLICIT  }, // physical palette index 3
           { 4,    0,    0,    PC_EXPLICIT  }, // physical palette index 4
           { 5,    0,    0,    PC_EXPLICIT  }, // physical palette index 5
           { 6,    0,    0,    PC_EXPLICIT  }, // physical palette index 6
           { 7,    0,    0,    PC_EXPLICIT  }, // physical palette index 7
           { 8,    0,    0,    PC_EXPLICIT  }, // physical palette index 8
           { 9,    0,    0,    PC_EXPLICIT  }, // physical palette index 9
           { 10,   0,    0,    PC_EXPLICIT  }, // physical palette index 10
           { 11,   0,    0,    PC_EXPLICIT  }, // physical palette index 11
           { 12,   0,    0,    PC_EXPLICIT  }, // physical palette index 12
           { 13,   0,    0,    PC_EXPLICIT  }, // physical palette index 13
           { 14,   0,    0,    PC_EXPLICIT  }, // physical palette index 14
           { 15,   0,    0,    PC_EXPLICIT  }, // physical palette index 15
           { 255,  0,    0,    PC_EXPLICIT  }  // Windows white
	}
};

typedef struct BMAPINFO
{
	BITMAPINFOHEADER	bmiHeader;
	union
	{
		WORD			awColors[16];
		RGBQUAD			aRGBQuad[16];
	} u;
} BMAPINFO;

BMAPINFO DIBHdr =
{
	{
		sizeof(BITMAPINFOHEADER),	// biSize
		64,				// biWidth
		64,				// biHeight
		1,				// biPlanes
		4,				// biBitCount
		BI_RGB,				// biCompression
		2048,				// biSizeImage
		0,				// biXPelsPerMeter
		0,				// biYPelsPerMeter
		0,				// biClrUsed
		0				// biClrImportant
	},
	// Here the indices map 1 to 1 with our logical palette, they may change
	// depending on the index of the first color but they always follow in order:
	{{0+pb,1+pb,2+pb,3+pb,4+pb,5+pb,6+pb,7+pb,8+pb,9+pb,10+pb,11+pb,12+pb,13+pb,14+pb,15+pb}}
};

static BYTE dib[] = {
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
	0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
	0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
	0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
	0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
	0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
	0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
	0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
	0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
	0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
	0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
	0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
	0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
	0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
	0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
	0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
	0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
	0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
	0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
	0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
	0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
	0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
	0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
	0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
	0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
	0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
	0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
	0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
	0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
	0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
	0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
	0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
	0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
	0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
	0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
	0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
	0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
	0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
	0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
	0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
	0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
	0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
	0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
	0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
	0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
	0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
	0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
	0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
	0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
	0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
	0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
	0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
	0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
	0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
	0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
	0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
	0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
	0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
	0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
	0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
	0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
	0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
	0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
};
#endif


//
// Forward declarations.
//
BOOL InitializeApp   (void);
LONG APIENTRY MainWndProc     (HWND, UINT, DWORD, LONG);
LONG APIENTRY DrawSurfWndProc (HWND, UINT, DWORD, LONG);
BOOL CALLBACK About           (HWND, UINT, DWORD, LONG);
LONG APIENTRY TextWndProc     (HWND, UINT, DWORD, LONG);
LONG APIENTRY CtrlPanelDlgProc(HWND, UINT, DWORD, LONG);
BOOL bDrawStuff      (HDC, INT, INT, INT, INT, BOOL, BOOL, BOOL, LPSTR);
HENHMETAFILE hemfLoadMetafile(HWND);
HDC  hDCRecordMetafileAs(HWND, LPSTR);
BOOL APIENTRY bPlayRecord(HDC, LPHANDLETABLE, LPENHMETARECORD, UINT, LPVOID);
BOOL APIENTRY bDoHitTest(HDC, LPHANDLETABLE, LPENHMETARECORD, UINT, LPVOID);
BOOL bHitTest(HDC, INT, INT);
HBITMAP hBmpLoadBitmapFile(HDC, PSTR);
BOOL bGetBMP(HWND, BOOL);
BOOL bChooseNewFont(HWND, PLOGFONT, COLORREF * );
BOOL bChooseNewColor(HWND, LPDWORD);
BOOL bPrintMf(PPRTDATA);
HBRUSH hBrCreateBrush(HDC, DWORD);
BOOL bSelectDIBPal(HDC, LPBITMAPINFO, BOOL);
BOOL bFreeDibFile(PDIBDATA);
BOOL bPlgBlt(HDC, LPPOINT);
HPALETTE CopyPalette(HPALETTE hPalSrc);
int CALLBACK iTT(LPLOGFONT, LPTEXTMETRIC, DWORD, LPARAM);
CMTMLTFMT *pLoadMltFmtFile(VOID);
HLOCAL Free(CMTMLTFMT *pMfmt);
BOOL bGetEPSBounds(LPVOID, RECTL *);
BOOL bIsAdobe(char *szStr);
BOOL bIsEPS(char *szStr);
BOOL bIsBndBox(char *szStr);
BOOL bIsEOF(char *szStr);
//BOOL bGetWord(LPVOID, char *, char **);
//BOOL bGoNextLine(LPVOID, char **);
BOOL bGetWord(LPVOID, char *, int*);
BOOL bGoNextLine(LPVOID, int*);

/***************************************************************************\
* WinMain
*
* History:
* 11-Feb-1992   Petrus Wong
\***************************************************************************/
int WINAPI WinMain(
#if 0
           HANDLE hInstance,
           HANDLE hPrevInstance,
#endif
           HINSTANCE hInstance,
           HINSTANCE hPrevInstance,
           LPSTR lpCmdLine,
           int nShowCmd)
{
    MSG    msg;
    HANDLE hAccel;

    ghModule = GetModuleHandle(NULL);
    if (!InitializeApp()) {
	MessageBox(ghwndMain, "MfEdit: InitializeApp failure!", "Error", MB_OK);
        return 0;
    }

    if (!(hAccel = LoadAccelerators (ghModule, MAKEINTRESOURCE(ACCEL_ID))))
	MessageBox(ghwndMain, "MfEdit: Load Accel failure!", "Error", MB_OK);


    while (GetMessage(&msg, NULL, 0, 0)) {
        if (!TranslateAccelerator( ghwndMain, hAccel, &msg) ) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return 1;

    UNREFERENCED_PARAMETER(lpCmdLine);
    UNREFERENCED_PARAMETER(nShowCmd);
    UNREFERENCED_PARAMETER(hInstance);
    UNREFERENCED_PARAMETER(hPrevInstance);
}


/***************************************************************************\
* InitializeApp
*
* History:
* 11-Feb-1992   Petrus Wong
*   Name changes.
* 09-09-91      Petrus Wong	Created.
\***************************************************************************/

BOOL InitializeApp(void)
{
    WNDCLASS wc;
    int index;
    HDC hDC;

    wc.style            = CS_DBLCLKS;
    wc.lpfnWndProc      = (WNDPROC)MainWndProc;
    wc.cbClsExtra       = 0;
    wc.cbWndExtra	= sizeof(DWORD);
    wc.hInstance        = ghModule;
    wc.hIcon            = LoadIcon(ghModule, MAKEINTRESOURCE(APP_ICON));
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground	= (HBRUSH)(COLOR_APPWORKSPACE + 1);
    wc.lpszMenuName     = "MainMenu";
    wc.lpszClassName	= "MetafDemoClass";

    if (!RegisterClass(&wc))
	return FALSE;

    wc.style            = CS_OWNDC | CS_SAVEBITS;
    wc.lpfnWndProc      = (WNDPROC)DrawSurfWndProc;
    wc.hIcon            = NULL;
    wc.hCursor          = NULL;
    wc.hbrBackground    = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = "DrawSurfClass";

    if (!RegisterClass(&wc))
	return FALSE;

    wc.style		= CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc	= (WNDPROC)TextWndProc;
    wc.hIcon		= NULL;
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground	= (HBRUSH)(COLOR_BTNFACE + 1);
    wc.lpszMenuName	= NULL;
    wc.lpszClassName	= "Text";

    if (!RegisterClass(&wc))
            return FALSE;



    hMenu	= LoadMenu(ghModule, "MainMenu");

    for (index = 0; index < OD_BTN_CNT; index++) {
        ghBmpDn[index] = (PVOID)LoadBitmap(ghModule, (LPCSTR)MAKEINTRESOURCE(BMID_BASED+index));
        ghBmpUp[index] = (PVOID)LoadBitmap(ghModule, (LPCSTR)MAKEINTRESOURCE(BMID_BASEU+index));
    }
    for (index = 0; index < OD_TOOL_CNT; index++) {
        ghToolBmpDn[index] = (PVOID)LoadBitmap(ghModule, (LPCSTR)MAKEINTRESOURCE(BMID_TOOLBASED+index));
        ghToolBmpUp[index] = (PVOID)LoadBitmap(ghModule, (LPCSTR)MAKEINTRESOURCE(BMID_TOOLBASEU+index));

    }

    ghwndMain = CreateWindowEx(0L, "MetafDemoClass", "Enhanced Metafile Editor",
	    WS_OVERLAPPED   | WS_CAPTION     | WS_BORDER       |
	    WS_THICKFRAME   | WS_MAXIMIZEBOX | WS_MINIMIZEBOX  |
	    WS_CLIPCHILDREN | WS_VISIBLE     | WS_SYSMENU,
            80, 70, 600, 300,
	    NULL, hMenu, ghModule, NULL);

    if (ghwndMain == NULL)
	return FALSE;

    SetWindowLong(ghwndMain, GWL_USERDATA, 0L);
    ghwndNext = SetClipboardViewer(ghwndMain);

    if (gbFit2Wnd)
        CheckMenuItem(hMenu, MM_FIT2WND, MF_CHECKED);
    else
        CheckMenuItem(hMenu, MM_FIT2WND, MF_UNCHECKED);

    if (gbImport3X)
        CheckMenuItem(hMenu, MM_IMPORT_3X, MF_CHECKED);
    else
        CheckMenuItem(hMenu, MM_IMPORT_3X, MF_UNCHECKED);

    if (gbExport3X)
        CheckMenuItem(hMenu, MM_EXPORT_3X, MF_CHECKED);
    else
        CheckMenuItem(hMenu, MM_EXPORT_3X, MF_UNCHECKED);

    SetFocus(ghwndMain);    /* set initial focus */

    gDib.ulFiles = gDib.ulFrames = 0;
    hDC = GetDC(NULL);
    ghHT = CreateHalftonePalette(hDC);
    ReleaseDC(NULL, hDC);

    return TRUE;
}


/***************************************************************************\
* MainWndProc
*
* History:
* 11-Feb-1992   Petrus Wong
*   Name changes.  Added comments.
* 09-09-91      Petrus Wong	Created.
\***************************************************************************/

long APIENTRY MainWndProc(
    HWND hwnd,
    UINT message,
    DWORD wParam,
    LONG lParam)
{
    static int         iMetafCnt=0;
    static char        szFilename[256] = "c:\\metaf";
    static BOOL        bReset=FALSE;
    static char        szLoadedMetaf[256] = " ";

    switch (message) {

      case WM_CREATE: {

	SetWindowLong(hwnd, 0, (LONG)NULL);
        ghDCMem = CreateCompatibleDC(NULL);

        ghwndCtrlPanel = CreateDialog(ghModule, (LPCSTR)MAKEINTRESOURCE(DID_CTRLPANEL),
                     hwnd, (DLGPROC) CtrlPanelDlgProc);

        ghwndDrawSurf = CreateWindow("DrawSurfClass", NULL,
                                    WS_BORDER | WS_CHILD | WS_VISIBLE,
                                    0, 0, 0, 0,
                                    hwnd,
                                    NULL,
                                    ghModule,
                                    NULL);

        ghTextWnd = CreateWindow("Text", NULL,
                                WS_BORDER | SS_LEFT | WS_CHILD | WS_VISIBLE,
                                0, 0, 0, 0,
                                hwnd,
                                NULL,               //(HMENU) 2,
                                ghModule,
                                NULL);

        ghbrRed = CreateSolidBrush(RGB(255, 0, 0));
        ghbrAppBkgd = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
        ghpnWide = CreatePen(PS_SOLID, 5, RGB(0, 0, 0));
        return 0L;
      }
      case WM_DRAWCLIPBOARD:
        if ((IsClipboardFormatAvailable(CF_METAFILEPICT)) ||
            (IsClipboardFormatAvailable(CF_ENHMETAFILE)) )
            EnableMenuItem(hMenu, MM_PASTE, MF_ENABLED);
        else
            EnableMenuItem(hMenu, MM_PASTE,  MF_GRAYED);

        if (ghwndNext)
            SendMessage(ghwndNext, message, wParam, lParam);
        return 0L;

      case WM_SIZE: {
          RECT        rc;
          LONG        lcyCtrlPanel, lcyDrawSurf;

          GetWindowRect(ghwndCtrlPanel, &rc);
          lcyCtrlPanel = rc.bottom-rc.top;
          lcyDrawSurf = HIWORD(lParam) - lcyCtrlPanel - glcyStatus;

          //
          // CR!! Alternatively, this window can be created with cy
          //      equals to cy of the screen and saving this call
          //      altogether.
          //
          MoveWindow(ghwndCtrlPanel,
                     0, 0, LOWORD(lParam), lcyCtrlPanel, TRUE);

          //
          // This ordering guarantees the text window paints correctly
          //
          MoveWindow(ghTextWnd,
                     0, lcyCtrlPanel + lcyDrawSurf,
                     LOWORD(lParam),                    // cx of hwnd
                     glcyStatus, TRUE);

          MoveWindow(ghwndDrawSurf,
                     0, lcyCtrlPanel,
                     LOWORD(lParam),                    // cx of hwnd
                     lcyDrawSurf, TRUE);
          //break;
          return DefWindowProc(hwnd, message, wParam, lParam);
      }

      case WM_DESTROY: {
        DeleteDC(ghDCMem);
        DeleteEnhMetaFile(ghMetaf);
        DestroyWindow(ghwndCtrlPanel);
        DeleteObject(ghbrRed);
        DeleteObject(ghbrCur);
        DeleteObject(ghpnCur);
        DeleteObject(ghbrAppBkgd);
        DeleteObject(ghpnWide);
        if (ghHT)
            DeleteObject(ghHT);
        ChangeClipboardChain(ghwndMain, ghwndNext);
        bFreeDibFile(&gDib);
	PostQuitMessage(0);
	return 0L;
      }

      case WM_COMMAND: {
        static int     iPlus=0;


	switch (LOWORD(wParam)) {
            case DID_ZERO:
            case DID_ONE:
            case DID_TWO:
            case DID_THREE:
            case DID_FOUR:
            case DID_FIVE:
            case DID_SIX:
            case DID_SEVEN:
            case DID_EIGHT:
            case DID_NINE: {
                HDC           hDCDrawSurf;
                ENHMETAHEADER EnhMetaHdr;
                RECT          rcClientDS;
                int           iRecord;
                PLAYINFO      PlayInfo;

                if (ghMetaf == 0)
                    return 0L;

                GetEnhMetaFileHeader(ghMetaf, sizeof(EnhMetaHdr), &EnhMetaHdr);
                iRecord = LOWORD(wParam) - DID_ZERO + iPlus;
                SetDlgItemInt(ghwndCtrlPanel, DID_COUNTER, iRecord, FALSE);
                PlayInfo.iRecord = iRecord;
                PlayInfo.bPlayContinuous = FALSE;
                iPlus = 0;

                if ((EnhMetaHdr.nRecords > 1) && (iRecord > 0) &&
                    (iRecord <= (INT) EnhMetaHdr.nRecords)) {
                    hDCDrawSurf = GetDC(ghwndDrawSurf);
                    if (gbFit2Wnd) {
                        GetClientRect(ghwndDrawSurf, &rcClientDS);
                        EnumEnhMetaFile(hDCDrawSurf, ghMetaf, (ENHMFENUMPROC)bPlayRecord, (LPVOID) &PlayInfo, &rcClientDS);
                    } else {
                        EnumEnhMetaFile(hDCDrawSurf, ghMetaf, (ENHMFENUMPROC)bPlayRecord, (LPVOID) &PlayInfo, (LPRECT)&EnhMetaHdr.rclBounds);
                    }
                    //
                    // Enabling the user to record a metafile record selectively
                    //
                    if ((gbRecording) && (ghDCMetaf != NULL)) {
                        EnumEnhMetaFile(ghDCMetaf, ghMetaf, (ENHMFENUMPROC)bPlayRecord, (LPVOID) &PlayInfo, (LPRECT)&EnhMetaHdr.rclBounds);
                    }
                    ReleaseDC(ghwndDrawSurf, hDCDrawSurf);
                }
                return 0L;
            }
            case DID_TEN_PLUS: {
                if (ghMetaf == 0)
                    return 0L;

                iPlus += 10;
                SetDlgItemInt(ghwndCtrlPanel, DID_COUNTER, iPlus, FALSE);
                return 0L;
            }
            case MM_PAGESETUP:
            case MM_CUT:
                return 0L;

            case MM_COPY:   {

                if ((ghMetaf == 0) && (ghmf == 0)) {
                    SetWindowText(ghTextWnd, "No Metafile for copying");
                    return 0L;
                }

                OpenClipboard(ghwndMain);
                EmptyClipboard();

                if (gbExport3X)
                {
                    HGLOBAL          hmem;
                    LPMETAFILEPICT  lpmfp;
                    RECT            rcClientDS;
                    DWORD           x, y, mm;
                    HDC             hDCDrawSurf;
                    LPBYTE          pjData;
                    UINT            uiSize;

                    hDCDrawSurf = GetDC(ghwndDrawSurf);

                    if (ghmf == 0) {
                        SetWindowText(ghTextWnd, "Converting Enhanced Metafile to 3X format");

                        if (!(uiSize = GetWinMetaFileBits(ghMetaf, 0, NULL, MM_ANISOTROPIC, hDCDrawSurf))) {
                            MessageBox(ghwndMain, "Fail in 1st GetWinMetaFileBits!", "Error", MB_OK);
                            goto COPY_3X_EXIT;
                        }

                        if ((pjData = (LPBYTE) LocalAlloc(LMEM_FIXED, uiSize)) == NULL) {
                            MessageBox(ghwndMain, "Fail in Memory Allocation!", "Error", MB_OK);
                            goto COPY_3X_EXIT;
                        }

                        if (!(uiSize = GetWinMetaFileBits(ghMetaf, uiSize, pjData, MM_ANISOTROPIC, hDCDrawSurf))) {
                            MessageBox(ghwndMain, "Fail in 2nd GetWinMetaFileBits!", "Error", MB_OK);
                            LocalFree(pjData);
                            goto COPY_3X_EXIT;
                        }

                        ghmf = SetMetaFileBitsEx(uiSize, (LPBYTE) pjData);
                        LocalFree(pjData);
                    }

                    if ((hmem = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE,
                                        sizeof(METAFILEPICT))) == NULL) {

                        SetWindowText(ghTextWnd, "Failed in allocating memory");
                        goto COPY_3X_EXIT;

                    }

                    lpmfp = (LPMETAFILEPICT)GlobalLock(hmem);
                    lpmfp->mm = mm = MM_ANISOTROPIC;

                    GetClientRect(ghwndDrawSurf, &rcClientDS);
                    x = rcClientDS.right - rcClientDS.left;
                    x *= 2540;
                    x /= GetDeviceCaps(hDCDrawSurf, LOGPIXELSX);
                    lpmfp->xExt = x;                                // ie. in 0.01mm

                    y = rcClientDS.bottom - rcClientDS.top;
                    y *= 2540;
                    y /= GetDeviceCaps(hDCDrawSurf, LOGPIXELSY);
                    lpmfp->yExt = y;                                // ie. in 0.01mm

                    lpmfp->hMF = CopyMetaFile(ghmf, NULL);

                    GlobalUnlock(hmem);
                    SetWindowText(ghTextWnd, "Copying 3X Metafile to Clipboard");
                    SetClipboardData(CF_METAFILEPICT, hmem);

COPY_3X_EXIT:
                    ReleaseDC(ghwndDrawSurf, hDCDrawSurf);
                    goto COPY_EXIT;

                }

                //
                // gbExport3X == FALSE
                //
                if (ghMetaf == 0)           // requires conversion
                {
                    UINT            uiSize;
                    LPVOID          pvData;
                    HDC             hDCDrawSurf;

                    SetWindowText(ghTextWnd, "Converting 3X Metafile to Enhanced Metafile format");
                    if (!(uiSize = GetMetaFileBitsEx(ghmf, 0, NULL))) {
                        MessageBox(ghwndMain, "Fail in 1st GetMetaFileBitsEx!", "Error", MB_OK);
                        SetWindowText(ghTextWnd, "Conversion Failed");
                        goto COPY_EXIT;
                    }

                    if ((pvData = (LPVOID) LocalAlloc(LMEM_FIXED, uiSize)) == NULL) {
                        MessageBox(ghwndMain, "Fail in Memory Allocation!", "Error", MB_OK);
                        SetWindowText(ghTextWnd, "Conversion Failed");
                        goto COPY_EXIT;
                    }

                    if (!(uiSize = GetMetaFileBitsEx(ghmf, uiSize, pvData))) {
                        MessageBox(ghwndMain, "Fail in 2nd GetMetaFileBitsEx!", "Error", MB_OK);
                        goto COPY_ENH_EXIT;
                    }

                    hDCDrawSurf = GetDC(ghwndDrawSurf);

                    // !!! provide the correct picture extents in the METAFILEPICT structure
                    // where possible
                    ghMetaf = SetWinMetaFileBits(uiSize, (LPBYTE)pvData, hDCDrawSurf, NULL);

COPY_ENH_EXIT:
                    LocalFree(pvData);
                    ReleaseDC(ghwndDrawSurf ,hDCDrawSurf);

                    if (ghMetaf == 0) {
                        SetWindowText(ghTextWnd, "Conversion Failed");
                        goto COPY_EXIT;
                    }

                }

                //
                // No Conversion required
                //
                {

                    HENHMETAFILE hEmfTmp;

                    hEmfTmp = CopyEnhMetaFile(ghMetaf, NULL);

                    if (hEmfTmp) {
                        SetWindowText(ghTextWnd, "Copying Enhanced Metafile to Clipboard");
                        SetClipboardData(CF_ENHMETAFILE, hEmfTmp);
                        DeleteEnhMetaFile(hEmfTmp);
                    }

                }

COPY_EXIT:

                CloseClipboard();
                return 0L;
            }

            case MM_PASTE:  {
                OpenClipboard(ghwndMain);

                if (gbImport3X)
                {
                    HANDLE      hmem;
                    DWORD       dwXSugExt, dwYSugExt, dwMM;
                    HDC         hDCDrawSurf;
                    RECT        rc;
                    INT         iSavedDC;


                    hmem = GetClipboardData(CF_METAFILEPICT);

                    if (hmem)
                    {
                        LPMETAFILEPICT lpmfp;

                        SetWindowText(ghTextWnd, "Pasting 3X Metafile");
                        lpmfp = (LPMETAFILEPICT)GlobalLock(hmem);
                        ghmf  = lpmfp->hMF;
                        dwMM  = lpmfp->mm;
                        dwXSugExt = lpmfp->xExt;        // in 0.01 mm
                        dwYSugExt = lpmfp->yExt;
                        GlobalUnlock(hmem);

                        hDCDrawSurf = GetDC(ghwndDrawSurf);

                        iSavedDC = SaveDC(hDCDrawSurf);

                        GetClientRect(ghwndDrawSurf, &rc);

                        SetMapMode(hDCDrawSurf, dwMM);
                        if ((dwXSugExt > 0 )&& (dwYSugExt > 0))
                        {                               // suggested width & height of image
                            DWORD x;
                            DWORD y;

                            // no. of pixels in x and y
                            x = dwXSugExt;
                            x *= GetDeviceCaps(hDCDrawSurf,LOGPIXELSX);
                            x /= 2540;

                            y = dwYSugExt;
                            y *= GetDeviceCaps(hDCDrawSurf,LOGPIXELSY);
                            y /= 2540;

                            SetWindowExtEx(hDCDrawSurf, x, y, NULL);

                            if (gbFit2Wnd)
                                SetViewportExtEx(hDCDrawSurf, rc.right, rc.bottom, NULL);
                            else
                                SetViewportExtEx(hDCDrawSurf, x, y, NULL);

                        } else {
                            SetWindowText(ghTextWnd, "No information on 3X Metafile's extensions");
                            SetWindowExtEx(hDCDrawSurf, rc.right, rc.bottom, NULL);
                            SetViewportExtEx(hDCDrawSurf, rc.right, rc.bottom, NULL);
                        }

                        SetViewportOrgEx(hDCDrawSurf, 0, 0, NULL);
                        SetWindowOrgEx(hDCDrawSurf, 0, 0, NULL);

                        SetBoundsRect(hDCDrawSurf, NULL, DCB_ENABLE | DCB_SET);
                        PlayMetaFile(hDCDrawSurf, ghmf);
                        {
                        UINT    uiRC;
                        char    text[128];

                        wsprintf(text, "dwMM = %d\n", dwMM);
                        OutputDebugString(text);
                        wsprintf(text, "dwXSugExt = %d\n", dwXSugExt);
                        OutputDebugString(text);
                        wsprintf(text, "dwYSugExt = %d\n", dwYSugExt);
                        OutputDebugString(text);

                        uiRC = GetBoundsRect(hDCDrawSurf, &rc, DCB_RESET); // in logical coordinates
                        wsprintf(text, "GetBoundsRect = %d\n", uiRC);
                        OutputDebugString(text);
                        wsprintf(text, "left     = %d\n", rc.left);
                        OutputDebugString(text);
                        wsprintf(text, "right    = %d\n", rc.right);
                        OutputDebugString(text);
                        wsprintf(text, "top      = %d\n", rc.top);
                        OutputDebugString(text);
                        wsprintf(text, "bottom   = %d\n", rc.bottom);
                        OutputDebugString(text);
                        }

// !!!
// saving the wmf as an Aldus mf
//
{
OPENFILENAME    ofn;
char            szFile[256], szFileTitle[256];
static char     *szFilter;
UINT            uiSize;
HANDLE          hFile, hMapFile;
LPVOID          pMapFile;
DWORD           dwHigh, dwLow;

szFilter =
  "EnhMeta files Windows Metafiles (*.wmf)\0*.wmf\0\0";

strcpy(szFile, "*.wmf\0");
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = szFilter;
ofn.lpstrCustomFilter = (LPSTR) NULL;
ofn.nMaxCustFilter = 0L;
ofn.nFilterIndex = 1;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = sizeof(szFileTitle);
ofn.lpstrInitialDir = NULL;
ofn.lpstrTitle = "Save Metafile";
ofn.Flags = 0L;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = "WMF";

if (!GetOpenFileName(&ofn))
    return 0L;

uiSize = GetMetaFileBitsEx(ghmf, 0, NULL);
dwHigh = 0;
dwLow  = uiSize;

if ((hFile = CreateFile(szFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == (HANDLE)-1) {
    MessageBox(ghwndMain, "Fail in file open!", "Error", MB_OK);
    return 0L;
}

//
// Create a map file of the opened file
//
if ((hMapFile = CreateFileMapping(hFile, NULL,
                         PAGE_READWRITE, dwHigh, dwLow, "MapF")) == NULL) {
    MessageBox(ghwndMain, "Fail in creating map file!", "Error", MB_OK);
    goto ErrorExit1;
}

//
// Map a view of the whole file
//
if ((pMapFile = MapViewOfFile(hMapFile, FILE_MAP_WRITE, 0, 0, uiSize)) == NULL) {
    MessageBox(ghwndMain, "Fail in mapping view of the Map File object!", "Error", MB_OK);
    goto ErrorExit2;
}

if (uiSize) {
    APMFILEHEADER   AldHdr;
    PAPMFILEHEADER  pAldHdr;
    PBYTE           pjTmp;
    INT             iSize;
    char            text[128];

    AldHdr.key = ALDUS_ID;
    AldHdr.hmf = 0;                                 // Unused; must be zero
    AldHdr.bbox.Left   = 0;                         // in metafile units
    AldHdr.bbox.Top    = 0;
    //AldHdr.bbox.Right  = rc.right - rc.left;        // in logical coordinates
    //AldHdr.bbox.Bottom = rc.bottom - rc.top;

    switch (dwMM) {
        case MM_HIENGLISH:
            AldHdr.inch = 1000;
            AldHdr.bbox.Right  = (SHORT)dwXSugExt;
            AldHdr.bbox.Bottom = (SHORT)dwYSugExt;
            break;
        case MM_HIMETRIC:
            AldHdr.inch = 1440;
            AldHdr.bbox.Right  = (SHORT)(dwXSugExt / 2540 * 1440);
            AldHdr.bbox.Bottom = (SHORT)(dwYSugExt / 2540 * 1440);
            break;
        case MM_LOENGLISH:
            AldHdr.inch = 100;
            AldHdr.bbox.Right  = (SHORT)dwXSugExt;
            AldHdr.bbox.Bottom = (SHORT)dwYSugExt;
            break;
        case MM_LOMETRIC:
            AldHdr.inch = 254;
            AldHdr.bbox.Right  = (SHORT)dwXSugExt;
            AldHdr.bbox.Bottom = (SHORT)dwYSugExt;
            break;
        case MM_TEXT:
            AldHdr.inch = (WORD) (GetDeviceCaps(hDCDrawSurf, HORZRES) * 25.4 /
                          GetDeviceCaps(hDCDrawSurf, HORZSIZE));
            AldHdr.bbox.Right  = (SHORT)dwXSugExt;
            AldHdr.bbox.Bottom = (SHORT)dwYSugExt;
            break;
        case MM_TWIPS:
            AldHdr.inch = 1440;
            AldHdr.bbox.Right  = (SHORT)dwXSugExt;
            AldHdr.bbox.Bottom = (SHORT)dwYSugExt;
            break;
        default:
            AldHdr.inch = 1440;
            AldHdr.bbox.Right  = (SHORT)(dwXSugExt / 2540 * 1440);
            AldHdr.bbox.Bottom = (SHORT)(dwYSugExt / 2540 * 1440);
            break;
    }

    wsprintf(text, "MM           = %d\n", dwMM);
    OutputDebugString(text);
    wsprintf(text, "AldHdr.inch  = %d\n", AldHdr.inch);
    OutputDebugString(text);

    AldHdr.reserved = 0;
    AldHdr.checksum = 0;
    {
    WORD    *p;

    for (p = (WORD *)&AldHdr, AldHdr.checksum = 0;
            p < (WORD *)&(AldHdr.checksum); ++p)
        AldHdr.checksum ^= *p;
    }

    pAldHdr = &AldHdr;
    pjTmp = (PBYTE)pMapFile;

    iSize = 22;

    //!!! use memcpy...
    while (iSize--) {
        *(((PBYTE)pjTmp)++) = *(((PBYTE)pAldHdr)++);
    }

    pMapFile = (PBYTE)pMapFile + 22;
    GetMetaFileBitsEx(ghmf, uiSize, pMapFile);
}


UnmapViewOfFile(pMapFile);

ErrorExit2:
  CloseHandle(hMapFile);
ErrorExit1:
  CloseHandle(hFile);
}

                        RestoreDC(hDCDrawSurf, iSavedDC);
                        ReleaseDC(ghwndDrawSurf, hDCDrawSurf);

                    } else {
                        SetWindowText(ghTextWnd, "Cannot get 3X metafile from clipboard!");
                    }

                    goto PASTE_EXIT;

                }

                //
                // gbImport3X == FALSE
                //
                {
                    HENHMETAFILE hEmfTmp;
                    ENHMETAHEADER EnhMetaHdr;

                    hEmfTmp = GetClipboardData(CF_ENHMETAFILE);
                    if (hEmfTmp) {
                        SetWindowText(ghTextWnd, "Pasting Enhanced Metafile");
                        DeleteEnhMetaFile(ghMetaf);
                        ghMetaf = CopyEnhMetaFile(hEmfTmp, NULL);
                        DeleteEnhMetaFile(hEmfTmp);
                        GetEnhMetaFileHeader(ghMetaf, sizeof(EnhMetaHdr), &EnhMetaHdr);
                        SetDlgItemInt(ghwndCtrlPanel, DID_COUNTER, EnhMetaHdr.nRecords, FALSE);
                        bReset = TRUE;
                    } else {
                        SetWindowText(ghTextWnd, "Cannot get Enhanced metafile from clipboard!");
                    }
                }
PASTE_EXIT:

                CloseClipboard();
                EnableMenuItem(hMenu, MM_COPY,  MF_ENABLED);
                return 0L;
            }

            case MM_DEL:    {
                OpenClipboard(ghwndMain);
                EmptyClipboard();
                CloseClipboard();
                return 0L;
            }

            case MM_PEN: {
                HDC     hDC;
                DWORD   dwRGB;

                if (bChooseNewColor(hwnd, &dwRGB)) {
                    hDC = GetDC(ghwndDrawSurf);
                    if (ghpnCur != NULL)
                        DeleteObject(ghpnCur);
                    ghpnCur = CreatePen(PS_SOLID, 1, dwRGB);
                    SelectObject(hDC, ghpnCur);
                    if (ghDCMetaf != NULL)
                        SelectObject(ghDCMetaf, ghpnCur);
                    ReleaseDC(ghwndDrawSurf, hDC);
                }
                return 0L;
            }
            case MM_BRUSH: {
                HDC     hDC;
                static DWORD   dwRGB=RGB(255, 255, 255);

                if (bChooseNewColor(hwnd, &dwRGB)) {
                    hDC = GetDC(ghwndDrawSurf);
                    if (ghbrCur != NULL)
                        DeleteObject(ghbrCur);
                    ghbrCur = hBrCreateBrush(hDC, dwRGB);
                    SelectObject(hDC, ghbrCur);
                    if (ghDCMetaf != NULL)
                        SelectObject(ghDCMetaf, ghbrCur);
                    ReleaseDC(ghwndDrawSurf, hDC);
                }
                return 0L;
            }
            case MM_FONT: {
                HDC     hDC;
                char    text[128];

                if (bChooseNewFont(ghwndMain, &glf, &gCrText)) {
                    ghCurFont = CreateFontIndirect(&glf);

                    hDC = GetDC(ghwndDrawSurf);
                    EnumFonts(hDC, glf.lfFaceName, (FONTENUMPROC)iTT, (LPARAM)&gbTT);
                    wsprintf(text, "gbTT = %d\n", gbTT);
                    //OutputDebugString(text);
                    ReleaseDC(ghwndDrawSurf, hDC);

                    if (ghDCMetaf != NULL)
                        SelectObject(ghDCMetaf, ghCurFont);
                }
                return 0L;
            }

            case MM_TTOUTLN_STROKEFILL: {
                gbSFOutln = (gbSFOutln ? FALSE : TRUE);
                if (gbSFOutln) {
                    CheckMenuItem(hMenu, MM_TTOUTLN_STROKEFILL, MF_CHECKED);
                    CheckMenuItem(hMenu, MM_TTOUTLN_POLYDRAW, MF_UNCHECKED);
                    gbPDOutln = FALSE;
                }
                return 0L;
            }

            case MM_TTOUTLN_POLYDRAW: {
                gbPDOutln = (gbPDOutln ? FALSE : TRUE);
                if (gbPDOutln) {
                    CheckMenuItem(hMenu, MM_TTOUTLN_STROKEFILL, MF_UNCHECKED);
                    CheckMenuItem(hMenu, MM_TTOUTLN_POLYDRAW, MF_CHECKED);
                    gbSFOutln = FALSE;
                }
                return 0L;
            }

            case MM_C_WND_MF:
                return 0L;
            case MM_C_BEGIN_GP:
            case MM_C_END_GP:
                return 0L;
            case MM_C_MLTFMTS: {
                CMTMLTFMT *pMfmt;

                if ((gbRecording) && (ghDCMetaf != NULL)) {
                    if ((pMfmt = pLoadMltFmtFile()) != NULL) {
                        GdiComment(ghDCMetaf,
                                   sizeof(CMTMLTFMT)+pMfmt->aemrformat[0].cbData,
                                   (CONST BYTE *) pMfmt);
                        Free(pMfmt);
                    }
                    else
                        MessageBox(ghwndMain,
                                   "Fail to load Multiformat file!",
                                   "Error",
                                   MB_OK);
                }

                return 0L;
            }
            case MM_HITTEST: {
                static BOOL bHitTest=FALSE;
                HWND        hwndRecBtn;

                bHitTest = (bHitTest ? FALSE : TRUE);
                hwndRecBtn = GetDlgItem(ghwndCtrlPanel, DID_RECORD);
                if (bHitTest) {
                    CheckMenuItem(hMenu, MM_HITTEST, MF_CHECKED);
                    EnableMenuItem(hMenu, MM_RECORD, MF_GRAYED);
                    EnableWindow(hwndRecBtn, FALSE);
                    gbHitTest = TRUE;
                } else {
                    CheckMenuItem(hMenu, MM_HITTEST, MF_UNCHECKED);
                    EnableMenuItem(hMenu, MM_RECORD, MF_ENABLED);
                    EnableWindow(hwndRecBtn, TRUE);
                    gbHitTest = FALSE;
                    return 0L;
                }

                if (ghMetaf == 0) {
                    SetWindowText(ghTextWnd, "No Metafile loaded for hit-testing");
                    return 0L;
                }
                return 0L;
            }

	    case MM_LEABOUT:
		if (DialogBox(ghModule, (LPCSTR)"AboutBox", ghwndMain, (DLGPROC)About) == -1)
			MessageBox(ghwndMain, "DEMO: About Dialog Creation Error!", "Error", MB_OK);
                return 0L;

	    case MM_ABOUT:
		if (DialogBox(ghModule, "AboutBox", ghwndMain, (DLGPROC)About) == -1)
		   MessageBox(ghwndMain, "DEMO: About Dialog Creation Error!", "Error", MB_OK);
		return 0L;

            case MM_LOAD_MASKBMP:
                SetWindowText(ghTextWnd, "Load Mask Bitmap");
                bGetBMP(hwnd, TRUE);
                return 0L;

            case MM_LOAD_BMP:
                SetWindowText(ghTextWnd, "Load Bitmap");
                bGetBMP(hwnd, FALSE);
                return 0L;

            case MM_SAVE_BMP:
                SetWindowText(ghTextWnd, "Save Drawing Surface as Bitmap");
                return 0L;

            case MM_LOAD:
	    case DID_OPEN: {
                ENHMETAHEADER EnhMetaHdr;
                HENHMETAFILE  hEmfTmp;

                SetWindowText(ghTextWnd, "Load Metafile");
                //
                // If user hit cancel, we still have the original metafile
                //
                //DeleteEnhMetaFile(ghMetaf);
                //ghMetaf = hemfLoadMetafile(hwnd);
                hEmfTmp = hemfLoadMetafile(hwnd);
                if (hEmfTmp != 0) {
                    char     szDesc[256];

                    DeleteEnhMetaFile(ghMetaf);
                    ghMetaf = CopyEnhMetaFile(hEmfTmp, NULL);
                    GetEnhMetaFileHeader(ghMetaf, sizeof(EnhMetaHdr), &EnhMetaHdr);
                    SetDlgItemInt(ghwndCtrlPanel, DID_COUNTER, EnhMetaHdr.nRecords, FALSE);
                    DeleteEnhMetaFile(hEmfTmp);
                    EnableMenuItem(hMenu, MM_COPY,  MF_ENABLED);
                    if (GetEnhMetaFileDescription(ghMetaf, 256, szDesc) != 0) {
                        char    szText[256];
                        char    *szTmp, szSource[256];

                        szTmp = (char *)strtok(szDesc, "\\0");
                        strcpy(szSource, szTmp);
                        szTmp = (char *)strtok(NULL, "\\0\\0");
                        wsprintf(szText, "Source: %s  Title: %s", szSource, szTmp);
                        SetWindowText(ghTextWnd, szText);
                        strcpy(szLoadedMetaf, szTmp);
                    } else {
                        strcpy(szLoadedMetaf, "");
                    }
                //} else {
                //    SetDlgItemInt(ghwndCtrlPanel, DID_COUNTER, 0, FALSE);
                }
                bReset = TRUE;
                return 0L;
            }
            case MM_RECORD:
                if (gbHitTest) {
                    SetWindowText(ghTextWnd, "Please CANCEL Hit Testing Mode First!");
                    return 0L;
                }

                SetWindowText(ghTextWnd, "Recording...");
                if (!gbRecording) {
                    ghDCMetaf = hDCRecordMetafileAs(hwnd, szFilename);
                }

                if (ghDCMetaf == NULL) {
                   SetWindowText(ghTextWnd, "ERROR: Failed in creating the metafile DC!");
                   return 0L;
                }

                // Parse the szFilename for the title and GdiComment the metafile with it.
                {
                    char    szComment[256];
                    char    *szTmp, szTmp2[256];

                    szTmp = (char *)strtok(szFilename, "\\");
                    strcpy(szTmp2, szTmp);
                    while (szTmp != NULL) {
                        szTmp = (char *)strtok(NULL, "\\");
                        if (szTmp != NULL) {
                            strcpy(szTmp2, szTmp);
                        }
                    }
                    szTmp = (char *)strtok(szTmp2, ".");
                    wsprintf((LPSTR) szComment, "MfEdit:\\0%s\\0\\0", szTmp);
#if 0
                    if (!GdiComment(ghDCMetaf, 256, szComment)) {
                        MessageBox(ghwndMain, "Fail in adding comment!", "Error", MB_OK);
                    }
#endif
                }

                gbRecording = TRUE;

                if (ghpnCur != NULL)
                    SelectObject(ghDCMetaf, ghpnCur);

                if (ghbrCur != NULL)
                    SelectObject(ghDCMetaf, ghbrCur);

                if (ghCurFont != NULL)
                    SelectObject(ghDCMetaf, ghCurFont);
                return 0L;

	    case DID_RECORD: {
                int  iWidthMM, iHeightMM, iWidthPels, iHeightPels, iMMPerPelX, iMMPerPelY;
                char szComment[256];
                char szTitle[256];
                RECT rc;
                HDC  hDC;


                if (gbHitTest) {
                    SetWindowText(ghTextWnd, "Please CANCEL Hit Testing Mode First!");
                    return 0L;
                }

                SetWindowText(ghTextWnd, "Recording...");
                if (!gbRecording) {

                    hDC = GetDC(hwnd);
                    iWidthMM    = GetDeviceCaps(hDC, HORZSIZE);
                    iHeightMM   = GetDeviceCaps(hDC, VERTSIZE);
                    iWidthPels  = GetDeviceCaps(hDC, HORZRES);
                    iHeightPels = GetDeviceCaps(hDC, VERTRES);
                    ReleaseDC(hwnd, hDC);
                    iMMPerPelX  = (iWidthMM * 100)/iWidthPels;
                    iMMPerPelY  = (iHeightMM * 100)/iHeightPels;
                    GetClientRect(ghwndDrawSurf, &rc);
                    rc.left   = rc.left * iMMPerPelX;
                    rc.top    = rc.top * iMMPerPelY;
                    rc.right  = rc.right * iMMPerPelX;
                    rc.bottom = rc.bottom * iMMPerPelY;

                    {
                       char szFilenameWithExt[256];
                       char suffix[20];
                       char szDesc[256];
                       char *szTmp, szTmp2[256];

                       //
                       // assemble a new metafile name with the emf extension from
                       // the generic szFilename
                       //
                       wsprintf((LPSTR) suffix, "%d.emf", iMetafCnt);
                       iMetafCnt++;
                       strcpy(szFilenameWithExt, szFilename);
                       strcat(szFilenameWithExt, suffix);

                       //
                       // parse szFilename for the title for description
                       //
                       szTmp = (char *)strtok(szFilename, "\\");
                       strcpy(szTmp2, szTmp);
                       while (szTmp != NULL) {
                           szTmp = (char *)strtok(NULL, "\\");
                           if (szTmp != NULL) {
                               strcpy(szTmp2, szTmp);
                           }
                       }
                       szTmp = (char *)strtok(szTmp2, ".");
                       strcpy(szTitle, szTmp);
                       wsprintf(szDesc, "SDK Enhanced Metafile Editor\\0%s\\0\\0", szTitle);
                       ghDCMetaf = CreateEnhMetaFile((HDC)NULL, szFilenameWithExt, (LPRECT)&rc, (LPSTR)szDesc);
                    }

                    if ((SetGraphicsMode(ghDCMetaf, GM_ADVANCED)) == 0) {
                       MessageBox(ghwndMain, "Fail in setting Advanced Graphics Mode!", "Error", MB_OK);
                    }
                }

                if (ghDCMetaf == NULL) {
                   SetWindowText(ghTextWnd, "ERROR: Failed in creating the metafile DC!");
                   return 0L;
                }
                wsprintf((LPSTR) szComment, "MfEdit:\\0%s\\0\\0", szTitle);
#if 0
                if (!GdiComment(ghDCMetaf, 256, szComment)) {
                    MessageBox(ghwndMain, "Fail in adding comment!", "Error", MB_OK);
                }
#endif
                gbRecording = TRUE;

                if (ghpnCur != NULL)
                    SelectObject(ghDCMetaf, ghpnCur);

                if (ghbrCur != NULL)
                    SelectObject(ghDCMetaf, ghbrCur);

                if (ghCurFont != NULL)
                    SelectObject(ghDCMetaf, ghCurFont);

                return 0L;
            }
	    case DID_STOP:
                SetWindowText(ghTextWnd, "Stop");
                if (gbRecording) {
                    ghMetaf = CloseEnhMetaFile(ghDCMetaf);
                    gbRecording = FALSE;
                }
                return 0L;

	    case DID_PLAY: {
                HDC hDCDrawSurf;
                ENHMETAHEADER EnhMetaHdr;
                RECT          rcClientDS;
                int           iEntries;
                PLOGPALETTE     plogPal;
                PBYTE           pjTmp;
                HPALETTE        hPal;
                char            szTmp[256];

                wsprintf(szTmp, "Playing Metafile: %s", szLoadedMetaf);
                SetWindowText(ghTextWnd, szTmp);
                if (ghMetaf != NULL) {
                    hDCDrawSurf = GetDC(ghwndDrawSurf);
                    GetEnhMetaFileHeader(ghMetaf, sizeof(ENHMETAHEADER), &EnhMetaHdr);

                    iEntries = GetEnhMetaFilePaletteEntries(ghMetaf, 0, NULL);

                    if (iEntries) {
                        if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
                                sizeof(DWORD) + sizeof(PALETTEENTRY)*iEntries )) == NULL) {
                            MessageBox(ghwndMain, "Failed in Creating Palette!", "Error", MB_OK);
                        }

                        plogPal->palVersion = 0x300;
                        plogPal->palNumEntries = (WORD) iEntries;
                        pjTmp = (PBYTE) plogPal;
                        pjTmp += 8;

                        GetEnhMetaFilePaletteEntries(ghMetaf, iEntries, (PPALETTEENTRY)pjTmp);
                        hPal = CreatePalette(plogPal);
                        GlobalFree(plogPal);

                        SelectPalette(hDCDrawSurf, hPal, FALSE);
                        RealizePalette(hDCDrawSurf);
                    }


                    if (gbFit2Wnd) {
                        GetClientRect(ghwndDrawSurf, &rcClientDS);
                        if (!PlayEnhMetaFile( hDCDrawSurf, ghMetaf, (LPRECT) &rcClientDS)) {
                            char    text[128];

                            wsprintf(text, "Fail in PlayEnhMetaFile! Error %ld\n", GetLastError());
                            OutputDebugString(text);
                        }
                    } else {
                        RECT rc;

                        rc.top = rc.left = 0;
                        rc.right = EnhMetaHdr.rclBounds.right - EnhMetaHdr.rclBounds.left;
                        rc.bottom = EnhMetaHdr.rclBounds.bottom - EnhMetaHdr.rclBounds.top;
                        if (!PlayEnhMetaFile( hDCDrawSurf, ghMetaf, (LPRECT) &rc)) {
                            char    text[128];

                            wsprintf(text, "Fail in PlayEnhMetaFile! Error %ld\n", GetLastError());
                            OutputDebugString(text);
                        }

                    }
                    //
                    // Enabling the user to embed another metafile
                    //
                    if ((gbRecording) && (ghDCMetaf != NULL)) {
                        if (hPal != (HPALETTE)NULL) {
                            SelectPalette(ghDCMetaf, hPal, FALSE);
                            RealizePalette(ghDCMetaf);
                        }
                        {
                        RECT rc;

                        rc.top = rc.left = 0;
                        rc.right = EnhMetaHdr.rclBounds.right - EnhMetaHdr.rclBounds.left;
                        rc.bottom = EnhMetaHdr.rclBounds.bottom - EnhMetaHdr.rclBounds.top;
                        if (!PlayEnhMetaFile( ghDCMetaf, ghMetaf, (LPRECT) &rc)) {
                            char    text[128];

                            wsprintf(text, "Fail in PlayEnhMetaFile! Error %ld\n", GetLastError());
                            OutputDebugString(text);
                        }

                        }
                    }

                    ReleaseDC(ghwndDrawSurf, hDCDrawSurf);
                } else {
                    SetWindowText(ghTextWnd, "No Metafile for Playing");
                }

                return 0L;
            }
	    case DID_FF: {
                HDC           hDCDrawSurf;
                ENHMETAHEADER EnhMetaHdr;
                RECT          rcClientDS;
                static int    iRecord = 0;
                PLAYINFO      PlayInfo;
                int           iEntries;
                PLOGPALETTE     plogPal;
                PBYTE           pjTmp;
                HPALETTE        hPal;


                if (ghMetaf == 0)
                    return 0L;

                PlayInfo.iRecord = ++iRecord;
                PlayInfo.bPlayContinuous = TRUE;

                GetEnhMetaFileHeader(ghMetaf, sizeof(EnhMetaHdr), &EnhMetaHdr);
                SetDlgItemInt(ghwndCtrlPanel, DID_COUNTER, iRecord, FALSE);
                if ((EnhMetaHdr.nRecords > 1) && (iRecord <= (INT)EnhMetaHdr.nRecords)) {
                    hDCDrawSurf = GetDC(ghwndDrawSurf);

                    iEntries = GetEnhMetaFilePaletteEntries(ghMetaf, 0, NULL);

                    if (iEntries) {
                        if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
                                sizeof(DWORD) + sizeof(PALETTEENTRY)*iEntries )) == NULL) {
                            MessageBox(ghwndMain, "Failed in Creating Palette!", "Error", MB_OK);
                        }

                        plogPal->palVersion = 0x300;
                        plogPal->palNumEntries = (WORD) iEntries;
                        pjTmp = (PBYTE) plogPal;
                        pjTmp += 8;

                        GetEnhMetaFilePaletteEntries(ghMetaf, iEntries, (PPALETTEENTRY)pjTmp);
                        hPal = CreatePalette(plogPal);
                        GlobalFree(plogPal);

                        SelectPalette(hDCDrawSurf, hPal, FALSE);
                        RealizePalette(hDCDrawSurf);
                    }

                    if (gbFit2Wnd) {
                        GetClientRect(ghwndDrawSurf, &rcClientDS);
                        EnumEnhMetaFile(hDCDrawSurf, ghMetaf, (ENHMFENUMPROC)bPlayRecord, (LPVOID) &PlayInfo, (LPRECT) &rcClientDS);
                    } else {
                        EnumEnhMetaFile(hDCDrawSurf, ghMetaf, (ENHMFENUMPROC)bPlayRecord, (LPVOID) &PlayInfo, (LPRECT) &EnhMetaHdr.rclBounds);
                    }
                    //
                    // Enabling the user to record a metafile records selectively
                    //
                    if ((gbRecording) && (ghDCMetaf != NULL)) {
                        SelectPalette(ghDCMetaf, hPal, FALSE);
                        RealizePalette(ghDCMetaf);
                        EnumEnhMetaFile(ghDCMetaf, ghMetaf, (ENHMFENUMPROC)bPlayRecord, (LPVOID) &PlayInfo, (LPRECT)&EnhMetaHdr.rclBounds);
                    }

                    ReleaseDC(ghwndDrawSurf, hDCDrawSurf);
                }

                if ((iRecord == (INT) EnhMetaHdr.nRecords) || bReset) {
                    iRecord = 0;
                    if (bReset)
                        SetDlgItemInt(ghwndCtrlPanel, DID_COUNTER, 0, FALSE);
                    bReset = FALSE;
                }
                return 0L;
            }
	    case DID_CLEAR: {
                HDC     hDCDrawSurf;
                HGDIOBJ hObjOld;
                RECT    rcDrawSurf;

                SetWindowText(ghTextWnd, "Drawing Surface cleared");
                hDCDrawSurf = GetDC(ghwndDrawSurf);
                ghbrAppBkgd = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
                hObjOld = SelectObject(hDCDrawSurf, ghbrAppBkgd);
                GetClientRect(ghwndDrawSurf, &rcDrawSurf);
                PatBlt(hDCDrawSurf, 0, 0, rcDrawSurf.right, rcDrawSurf.bottom, PATCOPY);
                ReleaseDC(ghwndDrawSurf, hDCDrawSurf);
                SelectObject(hDCDrawSurf, hObjOld);
                return 0L;
            }

            case DID_PEN:
                SetWindowText(ghTextWnd, "Pen");
                return 0L;
            case DID_TEXT:
                SetWindowText(ghTextWnd, "Text");
                return 0L;
            case DID_RECT:
                SetWindowText(ghTextWnd, "Rectangle");
                return 0L;
            case DID_FILLRECT:
                SetWindowText(ghTextWnd, "Filled Rectangle");
                return 0L;
            case DID_ELLIPSE:
                SetWindowText(ghTextWnd, "Ellipse");
                return 0L;
            case DID_FILLELLIPSE:
                SetWindowText(ghTextWnd, "Filled Ellipse");
                return 0L;
            case DID_LINE:
                SetWindowText(ghTextWnd, "Line");
                return 0L;
            case DID_BEZIER:
                SetWindowText(ghTextWnd,
                    "Bezier: Click with Left button for placing control points");
                return 0L;
            case DID_BMPOBJ:
                SetWindowText(ghTextWnd,
                    "Bitmap: Click three points for the destination of the bitmap");
                return 0L;
            case DID_METAF:
                SetWindowText(ghTextWnd,
                    "External Metafile: Click three points for the destination of the Metafile");
                return 0L;
            case MM_IMPORT_3X:
                gbImport3X = (gbImport3X ? FALSE : TRUE);

                if (gbImport3X)
                    CheckMenuItem(hMenu, MM_IMPORT_3X, MF_CHECKED);
                else
                    CheckMenuItem(hMenu, MM_IMPORT_3X, MF_UNCHECKED);
                return 0L;

            case MM_EXPORT_3X:
                gbExport3X = (gbExport3X ? FALSE : TRUE);

                if (gbExport3X)
                    CheckMenuItem(hMenu, MM_EXPORT_3X, MF_CHECKED);
                else
                    CheckMenuItem(hMenu, MM_EXPORT_3X, MF_UNCHECKED);
                return 0L;
            case MM_FIT2WND:
                gbFit2Wnd = (gbFit2Wnd ? FALSE : TRUE);

                if (gbFit2Wnd)
                    CheckMenuItem(hMenu, MM_FIT2WND, MF_CHECKED);
                else
                    CheckMenuItem(hMenu, MM_FIT2WND, MF_UNCHECKED);
                return 0L;

            case MM_PRINT: {
                DWORD   dwThrdID;
                HANDLE  hThrd;
                PPRTDATA pPrtData;

                if (ghMetaf == 0) {
                    SetWindowText(ghTextWnd, "NO Metafile to print");
                    return 0L;
                }

                //
                // bPrintMf is supposed to free up the memory when done.
                //
                if ((pPrtData = (PPRTDATA) GlobalAlloc(GPTR, sizeof(PRTDATA))) == NULL) {
                    SetWindowText(ghTextWnd, "Failed in allocating memory");
                    return 0L;
                }

                pPrtData->hMetaf = ghMetaf;
                pPrtData->bFit2Wnd = gbFit2Wnd;

                hThrd = CreateThread(NULL, 0,
                             (LPTHREAD_START_ROUTINE)bPrintMf,
                             pPrtData, STANDARD_RIGHTS_REQUIRED,
                             &dwThrdID);

                //
                // Free the memory if CreateThread fails...
                //
                if (hThrd == NULL) {
                    SetWindowText(ghTextWnd, "Failed in creating printing thread");
                    GlobalFree(pPrtData);
                }

                return 0L;

            }

	    default:
                return DefWindowProc(hwnd, message, wParam, lParam);
        }
      }     // WM_COMMAND
      default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
}

/******************************Public*Routine******************************\
*
* DrawSurfWndProc
*       Drawing surface window procedure
*
* Effects:  Trapping all mouse messages and call the DrawStuff appropriately
*           for drawing to the drawing surface DC and metafile DC as needed.
*
* Warnings:
*
* History:
*  30-Apr-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

long APIENTRY DrawSurfWndProc(
    HWND hwnd,
    UINT message,
    DWORD wParam,
    LONG lParam)
{
    static BOOL    bTrack = FALSE;
    static int     OrgX, OrgY;
    static int     PrevX, PrevY;
    static HDC     hDC;
    static HCURSOR hCurArrow, hCurHT;

    switch (message) {
      case WM_CREATE:
          {
              RECT       rect;

              hDC = GetDC(hwnd);
              if ((SetGraphicsMode(hDC, GM_ADVANCED)) == 0) {
                 MessageBox(ghwndMain, "Fail in setting Advanced Graphics Mode!", "Error", MB_OK);
              }
              ReleaseDC(hwnd, hDC);

              GetClientRect(GetParent(hwnd), &rect);

              SetWindowPos(hwnd, NULL,
                      0,
                      30,
                      rect.right-rect.left,
                      rect.bottom-rect.top-30,
                      SWP_NOZORDER | SWP_NOMOVE);

#if 0
//CreateCaret(hwnd, NULL, 1, 12);
//hbmp = LoadBitmap(ghModule, (LPCSTR)MAKEINTRESOURCE(BMID_TOOLBASED));

hPal = CreatePalette((LOGPALETTE *)&LogPal);
hDC = GetDC(hwnd);
hOldPal = SelectPalette(hDC, hPal, FALSE);
RealizePalette(hDC);

hbmp = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)&DIBHdr, CBM_CREATEDIB, &dib, (LPBITMAPINFO)&DIBHdr, DIB_PAL_COLORS);
CreateCaret(hwnd, hbmp, 1, 12);

ReleaseDC(hwnd, hDC);
#endif

              ghCurFont = GetStockObject(SYSTEM_FONT);
              GetObject(ghCurFont, sizeof(LOGFONT), &glf);
              hCurArrow = LoadCursor(NULL, IDC_ARROW);
              hCurHT = LoadCursor(NULL, IDC_CROSS);
              break;
          }

      case WM_LBUTTONDOWN: {
        int    x, y;

        x = (int) LOWORD(lParam);
        y = (int) HIWORD(lParam);

        if (gbHitTest) {
            hDC = GetDC(hwnd);
            bHitTest(hDC, x, y);
            ReleaseDC(hwnd, hDC);
            break;
        }

        bTrack = TRUE;
        OrgX = PrevX = x;
        OrgY = PrevY = y;

        hDC = GetDC(hwnd);
        SetCapture(hwnd);
        break;
      }

      case WM_MOUSEMOVE: {
        RECT rectClient;
        int NextX;
        int NextY;

        if (gbHitTest) {
            SetCursor(hCurHT);
        } else {
            SetCursor(hCurArrow);
        }

        // Update the selection region
        if (bTrack) {
            NextX = (SHORT) LOWORD(lParam);
            NextY = (SHORT) HIWORD(lParam);

            // Do not draw outside the window's client area

            GetClientRect (hwnd, &rectClient);
            if (NextX < rectClient.left) {
                NextX = rectClient.left;
            } else if (NextX >= rectClient.right) {
                NextX = rectClient.right - 1;
            }
            if (NextY < rectClient.top) {
                NextY = rectClient.top;
            } else if (NextY >= rectClient.bottom) {
                NextY = rectClient.bottom - 1;
            }
            if ((NextX != PrevX) || (NextY != PrevY)) {
               SetROP2(hDC, R2_NOT);           // Erases the previous box
               bDrawStuff(hDC, OrgX, OrgY, PrevX, PrevY, TRUE, TRUE, FALSE, NULL);

               //
               // Optimization.  Do not record in metafile DC if it is going
               // to be erased.  So only call bDrawStuff with the PEN tool.
               //
               if (gbRecording && (ghDCMetaf != NULL) && (gdwCurTool == DID_PEN)) {
                   bDrawStuff(ghDCMetaf, OrgX, OrgY, PrevX, PrevY, TRUE, TRUE, FALSE, NULL);
               }


            // Get the current mouse position
               PrevX = NextX;
               PrevY = NextY;

               //
               // SetROP2(hDC, R2_COPYPEN);
               //   This is commented out because we don't want to erase
               //   the background as it sweeps.
               //
               bDrawStuff(hDC, OrgX, OrgY, PrevX, PrevY, FALSE, TRUE, FALSE, NULL);

               if (gbRecording && (ghDCMetaf != NULL) && (gdwCurTool == DID_PEN)) {
                   bDrawStuff(ghDCMetaf, OrgX, OrgY, PrevX, PrevY, FALSE, TRUE, FALSE, NULL);
               }

            }
        }
        break;

      }

      case WM_LBUTTONUP: {
        int NextX;
        int NextY;

        if (!bTrack)
           break;

        // End the selection
           ReleaseCapture();
           bTrack = FALSE;

        // Erases the box
           //
           // SetROP2(hDC, R2_NOT);
           //   This is assumed to be R2_NOT, thus unnecessary
           //
           bDrawStuff(hDC, OrgX, OrgY, PrevX, PrevY, TRUE, FALSE, FALSE, NULL);

           if (gbRecording && (ghDCMetaf != NULL) && (gdwCurTool == DID_PEN)) {
               bDrawStuff(ghDCMetaf, OrgX, OrgY, PrevX, PrevY, TRUE, FALSE, FALSE, NULL);
           }

           NextX = (SHORT) LOWORD(lParam);
           NextY = (SHORT) HIWORD(lParam);

        // Draws the new box
           SetROP2(hDC, R2_COPYPEN);
           bDrawStuff(hDC, OrgX, OrgY, NextX, NextY, FALSE, FALSE, TRUE, NULL);

           ReleaseDC(hwnd, hDC);

           if (gbRecording && (ghDCMetaf != NULL)) {
                bDrawStuff(ghDCMetaf, OrgX, OrgY, NextX, NextY, FALSE, FALSE, FALSE, NULL);
           }

        break;
      } // case WM_LBUTTONUP

      case WM_CHAR: {

        if (gdwCurTool != DID_TEXT)
            break;

        hDC = GetDC(hwnd);
        bDrawStuff(hDC, 0, 0, 0, 0, TRUE, FALSE, FALSE, (LPSTR)&wParam);
        ReleaseDC(hwnd, hDC);

        if (gbRecording && (ghDCMetaf != NULL)) {
            bDrawStuff(ghDCMetaf, 0, 0, 0, 0, TRUE, FALSE, FALSE, (LPSTR)&wParam);
        }

        break;
      }

      case WM_DESTROY: {
        DestroyCaret();
        DeleteObject(ghCurFont);
	PostQuitMessage(0);
	return 0L;
      }

      default:
	return DefWindowProc(hwnd, message, wParam, lParam);
    }
}


/***************************************************************************\
* About
*
* About dialog proc.
*
* History:
* 09-09-91 Petrus Wong	Rewrote.
* 04-13-91 ????         Created.
\***************************************************************************/

BOOL CALLBACK About (
    HWND hDlg,
    UINT message,
    DWORD wParam,
    LONG lParam)
{
    switch (message) {
    case WM_INITDIALOG:
        return TRUE;

    case WM_COMMAND:
        if (wParam == IDOK)
            EndDialog(hDlg, wParam);
        break;
    }

    return FALSE;

    UNREFERENCED_PARAMETER(lParam);
    UNREFERENCED_PARAMETER(hDlg);
}

/***************************************************************************\
*
* TextWndProc
*
* Text Window procedure for displaying miscellaneous messages to user.
*
* History:
* 10-07-91  Petrus Wong
*   3D text output
*
\***************************************************************************/

LONG APIENTRY TextWndProc (HWND hwnd, UINT message, DWORD wParam, LONG lParam)
{
    static HFONT hFont = (HFONT) NULL;

    switch (message)
    {
    case WM_CREATE:
        {
	    LOGFONT    lf;
	    HDC        hDC;
	    HFONT      hOldFont;
            TEXTMETRIC tm;
	    //RECT       rect;

            SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), (PVOID) &lf, (UINT)FALSE);

	    hDC = GetDC(hwnd);
	    // this is the height for 8 point size font in pixels
	    lf.lfHeight = 8 * GetDeviceCaps(hDC, LOGPIXELSY) / 72;

	    hFont = CreateFontIndirect(&lf);
	    hOldFont = SelectObject(hDC, hFont);
	    GetTextMetrics(hDC, &tm);

	    // base the height of the window on size of text
	    glcyStatus = tm.tmHeight+6*GetSystemMetrics(SM_CYBORDER)+2;
            ReleaseDC(hwnd, hDC);
            break;
        }

    case WM_DESTROY:
	    if (hFont)
		DeleteObject(hFont);
	    break;

    case WM_SETTEXT:
            DefWindowProc(hwnd, message, wParam, lParam);
            InvalidateRect(hwnd,NULL,FALSE);
            UpdateWindow(hwnd);
            return 0L;

    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            RECT   rc;
            char   ach[128];
            int    len, nxBorder, nyBorder;
            HFONT  hOldFont = NULL;

            BeginPaint(hwnd, &ps);

            GetClientRect(hwnd,&rc);

            nxBorder = GetSystemMetrics(SM_CXBORDER);
	    rc.left  += 9*nxBorder;
            rc.right -= 9*nxBorder;

            nyBorder = GetSystemMetrics(SM_CYBORDER);
	    rc.top    += 3*nyBorder;
	    rc.bottom -= 3*nyBorder;

	    // 3D Text
            len = GetWindowText(hwnd, ach, sizeof(ach));
	    SetBkColor(ps.hdc, GetSysColor(COLOR_BTNFACE));

	    SetBkMode(ps.hdc, TRANSPARENT);
	    SetTextColor(ps.hdc, RGB(64,96,96));
	    if (hFont)
		hOldFont = SelectObject(ps.hdc, hFont);
	    ExtTextOut(ps.hdc, rc.left+2*nxBorder+2, rc.top+2, ETO_OPAQUE | ETO_CLIPPED,
	                &rc, ach, len, NULL);

	    SetTextColor(ps.hdc, RGB(128,128,128));
  	    if (hFont)
		hOldFont = SelectObject(ps.hdc, hFont);
	    ExtTextOut(ps.hdc, rc.left+2*nxBorder+1, rc.top+1, ETO_CLIPPED,
			&rc, ach, len, NULL);

	    SetTextColor(ps.hdc, RGB(255,255,255));
	    if (hFont)
		hOldFont = SelectObject(ps.hdc, hFont);
	    ExtTextOut(ps.hdc, rc.left+2*nxBorder, rc.top, ETO_CLIPPED,
			&rc, ach, len, NULL);

	    SetBkMode(ps.hdc, OPAQUE);

	    if (hOldFont)
		SelectObject(ps.hdc, hOldFont);

            EndPaint(hwnd, &ps);
            return 0L;
        }
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

/******************************Public*Routine******************************\
*
* CtrlPanelDlgProc
*       The Control Panel dialog procedure
*
* Effects:  Responsible for drawing the owner draw buttons.  Notifying
*           parent of user's action.
*
* Warnings:
*
* History:
*  27-May-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

LONG APIENTRY CtrlPanelDlgProc(HWND hwnd, UINT msg, DWORD dwParam, LONG lParam)
{
    switch (msg) {
        case WM_INITDIALOG: {
            int index;

            for (index = 0; index < OD_BTN_CNT; index++) {
                grHwndCtrlBtn[index] = (PVOID)GetDlgItem(hwnd, (INT)(ID_OD_BTN_BASE+index));
            }
            for (index = 0; index < OD_TOOL_CNT; index++) {
                grHwndToolBtn[index] = (PVOID)GetDlgItem(hwnd, (INT)(ID_OD_TOOL_BASE+index));
            }
            return TRUE;
        }

        case WM_DRAWITEM: {
            PDRAWITEMSTRUCT pDIS = (PDRAWITEMSTRUCT) lParam;
            HBITMAP hBmpOld;
            BITMAP  bm;
            HANDLE  hCtl;
            HDC     hDCCtl;

            if (pDIS->CtlID == gdwCurCtrl) {
                GetObject((HBITMAP) ghBmpDn[pDIS->CtlID - ID_OD_BTN_BASE], sizeof(BITMAP), (LPSTR)&bm);
                hBmpOld = SelectObject(ghDCMem, (HBITMAP) ghBmpDn[pDIS->CtlID - ID_OD_BTN_BASE]);
            }

            if (pDIS->CtlID == gdwCurTool) {
                GetObject((HBITMAP)ghToolBmpDn[pDIS->CtlID - ID_OD_TOOL_BASE], sizeof(BITMAP), (LPSTR)&bm);
                hBmpOld = SelectObject(ghDCMem, (HBITMAP)ghToolBmpDn[pDIS->CtlID - ID_OD_TOOL_BASE]);
            }

            if ((pDIS->CtlID < ID_OD_TOOL_BASE) && (pDIS->CtlID != gdwCurCtrl)) {
                GetObject((HBITMAP)ghBmpUp[pDIS->CtlID - ID_OD_BTN_BASE], sizeof(BITMAP), (LPSTR)&bm);
                hBmpOld = SelectObject(ghDCMem, (HBITMAP)ghBmpUp[pDIS->CtlID - ID_OD_BTN_BASE]);
            }

            if ((pDIS->CtlID >= ID_OD_TOOL_BASE) && (pDIS->CtlID != gdwCurTool)) {
                GetObject((HBITMAP)ghToolBmpUp[pDIS->CtlID - ID_OD_TOOL_BASE], sizeof(BITMAP), (LPSTR)&bm);
                hBmpOld = SelectObject(ghDCMem, (HBITMAP)ghToolBmpUp[pDIS->CtlID - ID_OD_TOOL_BASE]);
            }

            //
            // pDIS->hDC is clipped to the update region but unfortunately
            // that doesn't work well with StretchBlt.  StretchBlt is used
            // because I don't have to make sure that the bitmap size is
            // exactly the same as the size of the button.
            //
            hCtl   = GetDlgItem(hwnd, pDIS->CtlID);
            hDCCtl = GetDC(hCtl);
            StretchBlt(hDCCtl,                                //pDIS->hDC,
                   pDIS->rcItem.left, pDIS->rcItem.top,
                   pDIS->rcItem.right - pDIS->rcItem.left,
                   pDIS->rcItem.bottom - pDIS->rcItem.top,
                   ghDCMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
            ReleaseDC(hCtl, hDCCtl);
            SelectObject(ghDCMem, hBmpOld);
            break;
        }

        case WM_COMMAND: {
            DWORD dwOldCtrl = gdwCurCtrl;
            DWORD dwOldTool = gdwCurTool;

            switch (dwParam) {
                case DID_ONE:
                case DID_TWO:
                case DID_THREE:
                case DID_FOUR:
                case DID_FIVE:
                case DID_SIX:
                case DID_SEVEN:
                case DID_EIGHT:
                case DID_NINE:
                case DID_ZERO:
                case DID_TEN_PLUS:
                    //SetDlgItemInt(ghwndCtrlPanel, DID_COUNTER, dwParam - DID_ZERO, FALSE);
                    SendMessage(ghwndMain, WM_COMMAND, dwParam, lParam);
                    break;
                case DID_OPEN:
                case DID_RECORD:
                case DID_STOP:
                case DID_PLAY:
                case DID_FF:
                    SendMessage(ghwndMain, WM_COMMAND, dwParam, lParam);
                    gdwCurCtrl = dwParam;
                    InvalidateRect((HWND)grHwndCtrlBtn[dwOldCtrl - ID_OD_BTN_BASE], NULL, FALSE);
                    InvalidateRect((HWND)grHwndCtrlBtn[gdwCurCtrl - ID_OD_BTN_BASE], NULL, FALSE);
                    break;
                case DID_CLEAR:
                    SendMessage(ghwndMain, WM_COMMAND, dwParam, lParam);
                    break;
                case DID_TEXT:
                case DID_PEN:
                case DID_RECT:
                case DID_FILLRECT:
                case DID_ELLIPSE:
                case DID_FILLELLIPSE:
                case DID_LINE:
                case DID_BEZIER:
                case DID_BMPOBJ:
                case DID_METAF:
                    SendMessage(ghwndMain, WM_COMMAND, dwParam, lParam);
                    gdwCurTool = dwParam;
                    InvalidateRect((HWND)grHwndToolBtn[dwOldTool - ID_OD_TOOL_BASE], NULL, FALSE);
                    InvalidateRect((HWND)grHwndToolBtn[gdwCurTool - ID_OD_TOOL_BASE], NULL, FALSE);
                    break;
            }
            break;
        }


        case WM_PAINT:
            {
                HDC hdc;
                RECT rc, rcDlg;
                PAINTSTRUCT ps;
                HPEN hpenWindowFrame, hpenDarkGray;
                int  icyDlg;
                int  icyBorder;

                icyBorder = GetSystemMetrics(SM_CYBORDER);

                GetWindowRect(hwnd, &rcDlg);
                icyDlg = rcDlg.right - rcDlg.left;

                /*
                 * Draw our border lines.
                 */
                GetClientRect(hwnd, &rc);
                hdc = BeginPaint(hwnd, &ps);

                SelectObject(hdc, GetStockObject(WHITE_PEN));
                MoveToEx(hdc, rc.left, rc.top, NULL);
                LineTo(hdc, rc.right, rc.top);

                hpenDarkGray = CreatePen(PS_SOLID, 1, DARKGRAY);
                SelectObject(hdc, hpenDarkGray);
                MoveToEx(hdc, rc.left, (rc.top + icyDlg) - icyBorder - 1, NULL);
                LineTo(hdc, rc.right, (rc.top + icyDlg) - icyBorder - 1);

                hpenWindowFrame = CreatePen(PS_SOLID, icyBorder,
                        GetSysColor(COLOR_WINDOWFRAME));
                SelectObject(hdc, hpenWindowFrame);
                MoveToEx(hdc, rc.left, (rc.top + icyDlg) - icyBorder, NULL);
                LineTo(hdc, rc.right, (rc.top + icyDlg) - icyBorder);

                EndPaint(hwnd, &ps);
                DeleteObject(hpenWindowFrame);
                DeleteObject(hpenDarkGray);
            }

            break;


        //case WM_CTLCOLOR:
        case WM_CTLCOLORDLG:
        //case WM_CTLCOLORLISTBOX:
        case WM_CTLCOLORSTATIC:
            switch (GET_WM_CTLCOLOR_TYPE(dwParam, lParam, msg)) {
                case CTLCOLOR_DLG:
                //case CTLCOLOR_LISTBOX:
                    return (BOOL)GetStockObject(LTGRAY_BRUSH);

                case CTLCOLOR_STATIC:
                    SetBkMode(GET_WM_CTLCOLOR_HDC(dwParam, lParam, msg),
                              TRANSPARENT);
                //    SetTextColor(GET_WM_CTLCOLOR_HDC(dwParam, lParam, msg),
                //              RGB(255,0,0));
                //    SetBkColor(GET_WM_CTLCOLOR_HDC(dwParam, lParam, msg),
                //            LIGHTGRAY);
                //              RGB(255, 255,0));
                    return (BOOL)GetStockObject(DKGRAY_BRUSH);
            }
            //return (BOOL)NULL;
            return (BOOL)GetStockObject(LTGRAY_BRUSH);

        default:
            return FALSE;
    }

    return FALSE;
}



/******************************Public*Routine******************************\
*
* bDrawStuff
*
* Effects:  The drawing routines are localized here.
*           bErase is TRUE if this fcn is called for erasing previous object.
*           (as in tracking objects.)  It is FALSE, otherwise.
*
*           bMove is TRUE if this fcn is called inside the WM_MOUSEMOVE (as
*           in tracking objects.)  It is FALSE, otherwise.
*
*           bCntPt is TRUE if this fcn is to increment either the iCnt or
*           iCntMF counter (used only in processing metafile or bezier.)
*           It is FALSE, otherwise.
*
*           lpstr contains the character to be drawn by TextOut when it is
*           not NULL.
*
* Warnings: Metafile and Bezier assume that the caller is calling this fcn
*           to draw in the screen DC first. Then draw it to the metafile DC.
*           Thus, when it is called to draw on the metafile DC, the points
*           would have been set already.
*
* History:
*  10-May-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

BOOL bDrawStuff(HDC hDC, INT OrgX, INT OrgY,
                         INT NextX, INT NextY,
                         BOOL bErase,
                         BOOL bMove,
                         BOOL bCntPt,
                         LPSTR lpstr) {
    BOOL bSuccess;
    HGDIOBJ hObjOld;
    static POINT rgPts[MAX_POINTS], rgPtsMF[MAX_POINTS_MF], rgPtsBMP[MAX_POINTS_BMP];
    static int   iCnt=0, iCntMF=0, iCntBMP=0;
    static BOOL  bCaretShown=FALSE;

    bSuccess = TRUE;
    if (bCaretShown) {
        HideCaret(ghwndDrawSurf);
        bCaretShown = FALSE;
    }

    switch (gdwCurTool) {
        case DID_PEN:
            if (bErase) {
                MoveToEx(hDC, NextX, NextY, NULL);
            } else {
                //
                // Override the ROP2 st. the pen won't erase its track
                //
                SetROP2(hDC, R2_COPYPEN);
                LineTo(hDC, NextX, NextY);
            }
            break;
        case DID_TEXT: {
            POINT   Pt;
#if 0
HDC hDCMem;
#endif

            if (lpstr == NULL) {
                ShowCaret(ghwndDrawSurf);
                bCaretShown = TRUE;
                SetCaretPos(NextX, NextY);
                MoveToEx(hDC, NextX, NextY, NULL);

#if 0
StretchDIBits(hDC, 20, 20+120, 64, 64, 0, 64, 64, -64, &dib,
					(LPBITMAPINFO)&DIBHdr, DIB_PAL_COLORS, SRCCOPY);

hDCMem = CreateCompatibleDC(hDC);
SelectPalette(hDCMem, hPal, FALSE);
RealizePalette(hDCMem);
SelectObject(hDCMem, hbmp);
BitBlt(hDC, 0,0,64,64,hDCMem, 0,0,SRCCOPY);
DeleteDC(hDCMem);
#endif




                SetFocus(ghwndDrawSurf);
                break;
            }

            SetTextAlign(hDC, TA_BASELINE | TA_LEFT | TA_UPDATECP);
            hObjOld = SelectObject(hDC, ghCurFont);
            SetTextColor(hDC, gCrText);

            if ((gbSFOutln || gbPDOutln) && gbTT) {
                // get rid of the char box
                SetBkMode(hDC, TRANSPARENT);
                BeginPath(hDC);
                TextOut(hDC, NextX,    NextY,    lpstr, 1);
                EndPath(hDC);

                if (gbSFOutln) {
                    StrokeAndFillPath(hDC);
                    goto DT_UPDATE;
                }

                //
                // Get path and polydraw
                //
                {
                int     iNumPt;
                PBYTE   pjTypes;
                PPOINT  pPts;

                if (iNumPt = GetPath(hDC, NULL, NULL, 0)) {
                    if ((pPts = (PPOINT)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
                                                sizeof(POINT)*iNumPt )) == NULL) {
                        MessageBox(ghwndMain, "Failed in Creating POINT!", "Error", MB_OK);
                        break;
                    }

                    if ((pjTypes = (PBYTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
                                                sizeof(BYTE)*iNumPt )) == NULL) {
                        MessageBox(ghwndMain, "Failed in Creating PBYTE!", "Error", MB_OK);
                        goto GP_EXIT1;
                    }

                    GetPath(hDC, pPts, pjTypes, iNumPt);
                }
                PolyDraw(hDC, pPts, pjTypes, iNumPt);
                LocalFree(pjTypes);

GP_EXIT1:
                LocalFree(pPts);

                }

            } else {
                TextOut(hDC, NextX,    NextY,    lpstr, 1);
            }
DT_UPDATE:
            //
            // Updating current position
            //
            {
            LONG    lHeight;
            LONG    lWidth;
            TEXTMETRIC     tm;

                if (GetTextMetrics(hDC, &tm)) {
                    lHeight = tm.tmHeight;
                    lWidth  = tm.tmMaxCharWidth;
                }

                GetCurrentPositionEx(hDC, (LPPOINT) &Pt);
                SetCaretPos(Pt.x+lWidth, Pt.y);

            }
            ShowCaret(ghwndDrawSurf);
            bCaretShown = TRUE;

            break;

#if 0

#define PT_LINECLOSE     (PT_LINETO | PT_CLOSEFIGURE)
#define PT_BEZIERCLOSE (PT_BEZIERTO | PT_CLOSEFIGURE)

            hpnRed = CreatePen(PS_SOLID, 0, RGB(255,0,0));
            SelectObject(hDC, hpnRed);

            while (iNumPt--) {
                static POINT pPnt[3];
                static int   iCnt=0;

                switch (*pjTypes++) {
                    case PT_MOVETO: {
                        MoveToEx(hDC, pPts->x, pPts->y, NULL);
                        pPts++;
                        break;
                    }
                    case PT_LINETO: {
                        LineTo(hDC, pPts->x, pPts->y);
                        pPts++;
                        break;

                    }
                    case PT_LINECLOSE: {
                        LineTo(hDC, pPts->x, pPts->y);
                        pPts++;
                        goto GP_EXIT2;
                    }
                    case PT_BEZIERTO: {
                        pPnt[iCnt].x = pPts->x;
                        pPnt[iCnt].y = pPts->y;
                        pPts++;

                        if (iCnt < 2) {
                            iCnt++;
                        } else {
                            PolyBezierTo(hDC, pPnt, 3);
                            iCnt = 0;
                        }
                        break;
                    }
                    case PT_BEZIERCLOSE: {
                        pPnt[iCnt].x = pPts->x;
                        pPnt[iCnt].y = pPts->y;
                        pPts++;

                        if (iCnt < 2) {
                            iCnt++;
                        } else {
                            PolyBezierTo(hDC, pPnt, 3);
                            iCnt = 0;
                        }
                        goto GP_EXIT2;
                    }

                    default:
                        break;
                }

            }

#endif
        }
        case DID_RECT:
            hObjOld = SelectObject(hDC, GetStockObject(NULL_BRUSH));
            Rectangle(hDC, OrgX, OrgY, NextX, NextY);
            SelectObject(hDC, hObjOld);
            break;
        case DID_FILLRECT:
            Rectangle(hDC, OrgX, OrgY, NextX, NextY);
            break;
        case DID_ELLIPSE:
            hObjOld = SelectObject(hDC, GetStockObject(NULL_BRUSH));
            Ellipse(hDC, OrgX, OrgY, NextX, NextY);
            SelectObject(hDC, hObjOld);
            break;
        case DID_FILLELLIPSE:
            Ellipse(hDC, OrgX, OrgY, NextX, NextY);
            break;
        case DID_LINE:
            MoveToEx(hDC, OrgX, OrgY, NULL);
            LineTo(hDC, NextX, NextY);
            break;
        case DID_BEZIER:
            if (bErase || bMove)
                return bSuccess;

            if (bCntPt) {
                rgPts[iCnt].x = NextX;
                rgPts[iCnt].y = NextY;
                iCnt++;

                if (iCnt == MAX_POINTS - 1)
                    iCnt = 0;
            }

            if ((iCnt % 3) == 1) {              // (iCnt + 1) % 3 == 1
                //
                // Override the ROP2 st. the pen won't erase its track
                //
                SetROP2(hDC, R2_COPYPEN);
                PolyBezier(hDC, (LPPOINT)&rgPts, (DWORD) iCnt);
            }
            return bSuccess;

        case DID_BMPOBJ: {
            static BOOL          bBltReady = FALSE;

            if (bErase || bMove)
                return bSuccess;

            if (ghBmp == NULL) {
                SetWindowText(ghTextWnd, "ERROR: No bitmap to embed!");
                return bSuccess;
            }

            if (bCntPt) {
                bBltReady = FALSE;
                rgPtsBMP[iCntBMP].x = NextX;
                rgPtsBMP[iCntBMP].y = NextY;
                iCntBMP++;

                if (iCntBMP < MAX_POINTS_BMP) {
                    return bSuccess;
                }
            } else {
                //
                // Caller don't want to increment counter, so must be doing
                // recording, so we just Blt again...
                //
                // But, if the Blt data is no good, bail out...
                //
                if (!bBltReady) {
                    return bSuccess;
                }
                bPlgBlt(hDC, rgPtsBMP);
                return bSuccess;
            }
            bBltReady = TRUE;

            bPlgBlt(hDC, rgPtsBMP);
            iCntBMP = 0;                         // reset
            return bSuccess;
        }

        case DID_METAF: {
            ENHMETAHEADER EnhMetaHdr;
            RECT          rcClientDS;
            static XFORM         xform;
            static BOOL          bXformReady = FALSE;
            int           iEntries;
            PLOGPALETTE     plogPal;
            PBYTE           pjTmp;
            HPALETTE        hPal;


            if (bErase || bMove)
                return bSuccess;

            if (ghMetaf == NULL) {
                SetWindowText(ghTextWnd, "ERROR: No metafile to embed!");
                return bSuccess;
            }

            if (bCntPt) {
                bXformReady = FALSE;
                rgPtsMF[iCntMF].x = NextX;
                rgPtsMF[iCntMF].y = NextY;
                iCntMF++;

                if (iCntMF < MAX_POINTS_MF) {
                    return bSuccess;
                }
            } else {
                //
                // Caller don't want to increment counter, so must be doing
                // recording, so we just set xform and play it again...
                //
                // But, if the xform data is no good, bail out...
                //
                if (!bXformReady) {
                    return bSuccess;
                }

                GetEnhMetaFileHeader(ghMetaf, sizeof(ENHMETAHEADER), &EnhMetaHdr);
                SetWorldTransform(hDC, &xform);
                GetClientRect(ghwndDrawSurf, &rcClientDS);

                iEntries = GetEnhMetaFilePaletteEntries(ghMetaf, 0, NULL);

                if (iEntries) {
                    if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
                            sizeof(DWORD) + sizeof(PALETTEENTRY)*iEntries )) == NULL) {
                        MessageBox(ghwndMain, "Failed in Creating Palette!", "Error", MB_OK);
                    }

                    plogPal->palVersion = 0x300;
                    plogPal->palNumEntries = (WORD) iEntries;
                    pjTmp = (PBYTE) plogPal;
                    pjTmp += 8;

                    GetEnhMetaFilePaletteEntries(ghMetaf, iEntries, (PPALETTEENTRY)pjTmp);
                    hPal = CreatePalette(plogPal);
                    GlobalFree(plogPal);

                    SelectPalette(hDC, hPal, FALSE);
                    RealizePalette(hDC);
                }

                //PlayEnhMetaFile(hDC, ghMetaf, (LPRECT) &rcClientDS);
                {
                RECT rc;

                rc.top = rc.left = 0;
                rc.right = EnhMetaHdr.rclBounds.right - EnhMetaHdr.rclBounds.left;
                rc.bottom = EnhMetaHdr.rclBounds.bottom - EnhMetaHdr.rclBounds.top;
                if (!PlayEnhMetaFile(hDC, ghMetaf, (LPRECT) &rc)) {
                    char    text[128];

                    wsprintf(text, "Fail in PlayEnhMetaFile! Error %ld\n", GetLastError());
                    OutputDebugString(text);
                }

                }
                ModifyWorldTransform(hDC, NULL, MWT_IDENTITY);
                return bSuccess;
            }

            GetEnhMetaFileHeader(ghMetaf, sizeof(ENHMETAHEADER), &EnhMetaHdr);
            //
            // Based on the three points, top-left, top-right and bottom-left
            // (in this order), of the destination, solve equations for the
            // elements of the transformation matrix.
            //
            xform.eDx = (float) rgPtsMF[0].x;
            xform.eDy = (float) rgPtsMF[0].y;
            xform.eM11 = (rgPtsMF[1].x - xform.eDx)/(EnhMetaHdr.rclBounds.right - EnhMetaHdr.rclBounds.left);
            xform.eM12 = (rgPtsMF[1].y - xform.eDy)/(EnhMetaHdr.rclBounds.right - EnhMetaHdr.rclBounds.left);
            xform.eM21 = (rgPtsMF[2].x - xform.eDx)/(EnhMetaHdr.rclBounds.bottom - EnhMetaHdr.rclBounds.top);
            xform.eM22 = (rgPtsMF[2].y - xform.eDy)/(EnhMetaHdr.rclBounds.bottom - EnhMetaHdr.rclBounds.top);

            bXformReady = TRUE;
            SetWorldTransform(hDC, &xform);
            GetClientRect(ghwndDrawSurf, &rcClientDS);

            iEntries = GetEnhMetaFilePaletteEntries(ghMetaf, 0, NULL);

            if (iEntries) {
                if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
                        sizeof(DWORD) + sizeof(PALETTEENTRY)*iEntries )) == NULL) {
                    MessageBox(ghwndMain, "Failed in Creating Palette!", "Error", MB_OK);
                }

                plogPal->palVersion = 0x300;
                plogPal->palNumEntries = (WORD) iEntries;
                pjTmp = (PBYTE) plogPal;
                pjTmp += 8;

                GetEnhMetaFilePaletteEntries(ghMetaf, iEntries, (PPALETTEENTRY)pjTmp);
                hPal = CreatePalette(plogPal);
                GlobalFree(plogPal);

                SelectPalette(hDC, hPal, FALSE);
                RealizePalette(hDC);
            }

            //PlayEnhMetaFile(hDC, ghMetaf, (LPRECT) &rcClientDS);
            {
            RECT rc;

            rc.top = rc.left = 0;
            rc.right = EnhMetaHdr.rclBounds.right - EnhMetaHdr.rclBounds.left;
            rc.bottom = EnhMetaHdr.rclBounds.bottom - EnhMetaHdr.rclBounds.top;
            if (!PlayEnhMetaFile(hDC, ghMetaf, (LPRECT) &rc)) {
                 char    text[128];

                 wsprintf(text, "Fail in PlayEnhMetaFile! Error %ld\n", GetLastError());
                 OutputDebugString(text);
            }

            }
            ModifyWorldTransform(hDC, NULL, MWT_IDENTITY);
            iCntMF = 0;                         // reset
            return bSuccess;
        }
        default:
            break;
    }
    //
    // Reset counter, user has selected other tools.
    //
    iCnt = 0;
    iCntMF = 0;
    iCntBMP = 0;
    return bSuccess;
}

/******************************Public*Routine******************************\
*
* hemfLoadMetafile
*
* Effects:   Brings up the Open file common dialog
*            Get the enhanced metafile spec'd by user
*            returns the handle to the enhanced metafile if successfull
*               otherwise, returns 0.
*
* Warnings:
*
* History:
*  08-May-1992 -by- Petrus Wong
* Wrote it.
*  28-Aug-1992 -by- Petrus Wong     supports aldus placable mf, wmf and emf
\**************************************************************************/

HENHMETAFILE hemfLoadMetafile(HWND hwnd) {
    OPENFILENAME    ofn;
    char            szFile[256], szFileTitle[256];
    static char     *szFilter;

    HMETAFILE       hmf;
    UINT            uiSize;
    LPVOID          pvData;
    HDC             hDCDrawSurf;
    HENHMETAFILE    hemf;

    HANDLE                  hFile, hMapFile;
    LPVOID                  pMapFile;
    LPENHMETAHEADER         pemh;

    BOOL        bSuccess;
    char            text[128];


    bSuccess = TRUE;

    szFilter =
      "EnhMeta files (*.emf)\0*.emf\0Windows Metafiles (*.wmf)\0*.wmf\0\0";

    strcpy(szFile, "*.emf\0");
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFilter = szFilter;
    ofn.lpstrCustomFilter = (LPSTR) NULL;
    ofn.nMaxCustFilter = 0L;
    ofn.nFilterIndex = 1;
    ofn.lpstrFile = szFile;
    ofn.nMaxFile = sizeof(szFile);
    ofn.lpstrFileTitle = szFileTitle;
    ofn.nMaxFileTitle = sizeof(szFileTitle);
    ofn.lpstrInitialDir = NULL;
    ofn.lpstrTitle = "Load Metafile";
    ofn.Flags = 0L;
    ofn.nFileOffset = 0;
    ofn.nFileExtension = 0;
    ofn.lpstrDefExt = "EMF";

    if (!GetOpenFileName(&ofn))
        return 0L;

    if ((hFile = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ, NULL,
            OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL)) == (HANDLE)-1) {
        wsprintf(text, "Fail in file open! Error %ld\n", GetLastError());
        MessageBox(ghwndMain, text, "Error", MB_OK);
        return 0L;
    }

    //
    // Create a map file of the opened file
    //
    if ((hMapFile = CreateFileMapping(hFile, NULL,
                             PAGE_READONLY, 0, 0, "MapF")) == NULL) {
        wsprintf(text, "Fail in creating map file! Error %ld\n", GetLastError());
        MessageBox(ghwndMain, text, "Error", MB_OK);
        bSuccess = FALSE;
        goto ErrorExit1;
    }

    //
    // Map a view of the whole file
    //
    if ((pMapFile = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0)) == NULL) {
        wsprintf(text, "Fail in mapping view of the Map File object! Error %ld\n", GetLastError());
        MessageBox(ghwndMain, text, "Error", MB_OK);
        bSuccess = FALSE;
        goto ErrorExit2;
    }

    //
    // First check that if it is an enhanced metafile
    //
    pemh = (LPENHMETAHEADER) pMapFile;
    if (pemh->dSignature == META32_SIGNATURE) {
        hemf = GetEnhMetaFile(szFile);
        goto HLM_EXIT;
    }

    //
    // If it has an ALDUS header skip it
    // Notice: APMSIZE is used because the HANDLE and RECT of the structure
    //         depends on the environment
    //
    if (*((LPDWORD)pemh) == ALDUS_ID) {
        //METAFILEPICT    mfp;

        MessageBox(ghwndMain, "This is an ALDUS metafile!", "Hey!", MB_OK);
        uiSize = *((LPDWORD) ((PBYTE)pMapFile + APMSIZE + 6));
        hDCDrawSurf = GetDC(ghwndDrawSurf);

        // Notice: mtSize is size of the file in word.
        // if LPMETAFILEPICT is NULL
        //    MM_ANISOTROPIC mode and default device size will be used.
        hemf = SetWinMetaFileBits(uiSize*2L, (PBYTE)pMapFile + APMSIZE, hDCDrawSurf, NULL);
#if 0
        switch ( ((PAPMFILEHEADER) pMapFile)->inch ) {
            // !!! End up in an upside down image
            //
            case 1440:
                mfp.mm = MM_TWIPS;
                OutputDebugString("MM_TWIPS\n");
                break;
            case 2540:
                OutputDebugString("MM_HIMETRIC\n");
                mfp.mm = MM_HIMETRIC;
                break;
            case 254:
                OutputDebugString("MM_LOMETRIC\n");
                mfp.mm = MM_LOMETRIC;
                break;
            case 1000:
                OutputDebugString("MM_HIENGLISH\n");
                mfp.mm = MM_HIENGLISH;
                break;
            case 100:
                OutputDebugString("MM_LOENGLISH\n");
                mfp.mm = MM_LOENGLISH;
                break;
            default:
                // !!! In addition, text is too small
                //
                OutputDebugString("MM_ANISOTROPIC\n");
                mfp.mm = MM_ANISOTROPIC;
                mfp.xExt = (((PAPMFILEHEADER) pMapFile)->bbox.Right - ((PAPMFILEHEADER) pMapFile)->bbox.Left)
                           * ((PAPMFILEHEADER) pMapFile)->inch * 2560;
                mfp.yExt = (((PAPMFILEHEADER) pMapFile)->bbox.Bottom - ((PAPMFILEHEADER) pMapFile)->bbox.Top)
                           * ((PAPMFILEHEADER) pMapFile)->inch * 2560;
                break;
        }
        mfp.hMF = 0;
        hemf = SetWinMetaFileBits(uiSize*2L, (PBYTE)pMapFile + APMSIZE, hDCDrawSurf, &mfp);
#endif

        if (!hemf) {
            char text[256];

            wsprintf(text, "SetWinMetaFileBits failed, %x", GetLastError());
            MessageBox(ghwndMain, text, "Error!", MB_OK);
        }

        ghmf = SetMetaFileBitsEx(uiSize*2L, (PBYTE)pMapFile + APMSIZE);
        if (!ghmf) {
            char text[256];

            wsprintf(text, "SetMetaFileBitsEx failed, %x", GetLastError());
            MessageBox(ghwndMain, text, "Error!", MB_OK);
        }

// !!! Displaying the Windows format metafile
//if (!PlayMetaFile(hDCDrawSurf, ghmf)) {
//    wsprintf(text, "PlayMetaFile failed, %x", GetLastError());
//    MessageBox(ghwndMain, text, "Error!", MB_OK);
//}
        ReleaseDC(ghwndDrawSurf, hDCDrawSurf);
        goto HLM_EXIT;
    }


    //
    // It is a Windows 3x format metafile (hopefully)
    //
    if (!(hmf = GetMetaFile((LPCSTR)szFile))) {
        char text[256];

        wsprintf(text, "GetMetaFile failed, %x", GetLastError());
        MessageBox(ghwndMain, text, "Error!", MB_OK);
        bSuccess = FALSE;
        goto ErrorExit3;
    }

    if (!(uiSize = GetMetaFileBitsEx(hmf, 0, NULL))) {
        MessageBox(ghwndMain, "Fail in 1st GetMetaFileBitsEx!", "Error", MB_OK);
        return NULL;
    }

    if ((pvData = (LPVOID) LocalAlloc(LMEM_FIXED, uiSize)) == NULL) {
        MessageBox(ghwndMain, "Fail in Memory Allocation!", "Error", MB_OK);
        bSuccess = FALSE;
        goto ErrorExit3;
    }

    if (!(uiSize = GetMetaFileBitsEx(hmf, uiSize, pvData))) {
        MessageBox(ghwndMain, "Fail in 2nd GetMetaFileBitsEx!", "Error", MB_OK);
        bSuccess = FALSE;
        goto ErrorExit3;
    }

    DeleteMetaFile(hmf);

    hDCDrawSurf = GetDC(ghwndDrawSurf);
    hemf = SetWinMetaFileBits(uiSize, (LPBYTE)pvData, hDCDrawSurf, NULL);
    ghmf = SetMetaFileBitsEx(uiSize, (LPBYTE) pvData);

    LocalFree(pvData);

    ReleaseDC(ghwndDrawSurf ,hDCDrawSurf);

HLM_EXIT:
ErrorExit3:
    UnmapViewOfFile(pMapFile);

ErrorExit2:
    CloseHandle(hMapFile);
ErrorExit1:
    CloseHandle(hFile);

    if (bSuccess)
        return hemf;
    else
        return 0L;
}

/******************************Public*Routine******************************\
*
* hDCRecordMetafileAs
*
* Effects:   Brings up the SaveAs common dialog
*            Creates the enhanced metafile with the filename spec'd by user
*            Modifies the second arg to reflect the new default filename
*            less extension
*            returns the created metafile DC if successful, otherwise, 0
*
* Warnings:
*
* History:
*  08-May-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

HDC hDCRecordMetafileAs(HWND hwnd, LPSTR szFilename) {
    OPENFILENAME ofn;
    char szFile[256], szFileTitle[256];
    static char *szFilter;
    char *szTmp, szTmp2[256];
    HDC  hDCMeta;

    int iWidthMM, iHeightMM, iWidthPels, iHeightPels, iMMPerPelX, iMMPerPelY;
    RECT rc;
    HDC hDC;


    szFilter = "EnhMeta files (*.emf)\0\0";
    strcpy(szFile, "*.emf\0");
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFilter = szFilter;
    ofn.lpstrCustomFilter = (LPSTR) NULL;
    ofn.nMaxCustFilter = 0L;
    ofn.nFilterIndex = 0L;
    ofn.lpstrFile = szFile;
    ofn.nMaxFile = sizeof(szFile);
    ofn.lpstrFileTitle = szFileTitle;
    ofn.nMaxFileTitle = sizeof(szFileTitle);
    ofn.lpstrInitialDir = NULL;
    ofn.lpstrTitle = "Save Metafile As";
    ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;
    ofn.nFileOffset = 0;
    ofn.nFileExtension = 0;
    ofn.lpstrDefExt = (LPSTR)NULL;

    if (!GetSaveFileName(&ofn)) {
        return 0L;
    }


    hDC = GetDC(hwnd);
    iWidthMM = GetDeviceCaps(hDC, HORZSIZE);
    iHeightMM = GetDeviceCaps(hDC, VERTSIZE);
    iWidthPels = GetDeviceCaps(hDC, HORZRES);
    iHeightPels = GetDeviceCaps(hDC, VERTRES);
    ReleaseDC(hwnd, hDC);
    iMMPerPelX = (iWidthMM * 100)/iWidthPels;
    iMMPerPelY = (iHeightMM * 100)/iHeightPels;
    GetClientRect(ghwndDrawSurf, &rc);
    rc.left = rc.left * iMMPerPelX;
    rc.top = rc.top * iMMPerPelY;
    rc.right = rc.right * iMMPerPelX;
    rc.bottom = rc.bottom * iMMPerPelY;


    //hDCMeta = CreateEnhMetaFile((HDC)NULL, szFile, (LPRECT)NULL, (LPSTR)NULL);
    {
        CHAR    szDesc[256];

        wsprintf(szDesc, "SDK Enhanced Metafile Editor\\0%s\\0\\0", szFileTitle);
        hDCMeta = CreateEnhMetaFile((HDC)NULL, szFile, (LPRECT)&rc, (LPSTR)szDesc);
        if ((SetGraphicsMode(hDCMeta, GM_ADVANCED)) == 0) {
           MessageBox(ghwndMain, "Fail in setting Advanced Graphics Mode!", "Error", MB_OK);
        }
    }

    //
    // parses the new filename, removes the extension and copy it into
    // szFilename
    //
    strcpy(szFilename, "");
    szTmp = (char *)strtok(szFile, "\\");
    strcpy(szTmp2, szTmp);
    while (szTmp != NULL) {
        szTmp = (char *)strtok(NULL, "\\");
        if (szTmp != NULL) {
            strcat(szFilename, szTmp2);
            strcpy(szTmp2, szTmp);
            strcat(szFilename, "\\");
        }
    }
    szTmp = (char *)strtok(szTmp2, ".");
    strcat(szFilename, szTmp);

    return hDCMeta;
}


/******************************Public*Routine******************************\
*
* bPlayRecord
*
* Effects:  Play metafile
*           if PlayInfo.bPlayContinuous is TRUE
*               play metafile from 1st record up to the PlayInfo.iRecord th
*                   record
*           else only play the PlayInfo.iRecord th record and those preceding
*               records that are relevant like MoveTo, etc.
*           Terminates enumeration after playing up to the
*               PlayInfo.iRecord th record
*
* Warnings:
*
* History:
*  08-May-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

BOOL APIENTRY bPlayRecord(HDC hDC, LPHANDLETABLE lpHandleTable,
                                   LPENHMETARECORD lpEnhMetaRecord,
                                   UINT nHandles,
                                   LPVOID lpData) {
    BOOL bSuccess;
    static int  iCnt=0;
    int         i;
    char        ach[128];
    char        achTmp[128];
    LONG        lNumDword;

    bSuccess = TRUE;

    lNumDword = (lpEnhMetaRecord->nSize-8) / 4;

    iCnt++;
    if (((PLAYINFO *) lpData)->bPlayContinuous) {
        bSuccess = PlayEnhMetaFileRecord(hDC, lpHandleTable,
                                             lpEnhMetaRecord, nHandles);
        if (iCnt == ((PLAYINFO *) lpData)->iRecord) {
            wsprintf((LPSTR) ach, "%s", rgMetaName[lpEnhMetaRecord->iType]);
            for (i=0; i < lNumDword; i++) {
                wsprintf((LPSTR) achTmp, "%ld ", lpEnhMetaRecord->dParm[i]);
                if ((strlen(ach)+strlen(achTmp))/sizeof(char) >= 128)
                    break;
                strcat(ach, achTmp);
            }
        SetWindowText(ghTextWnd, ach);
        }
    } else {

        switch (lpEnhMetaRecord->iType) {
            case MR_SETWINDOWEXTEX:
            case MR_SETWINDOWORGEX:
            case MR_SETVIEWPORTEXTEX:
            case MR_SETVIEWPORTORGEX:
            case MR_SETBRUSHORGEX:
            case MR_SETMAPMODE:
            case MR_SETBKMODE:
            case MR_SETPOLYFILLMODE:
            case MR_SETROP2:
            case MR_SETSTRETCHBLTMODE:
            case MR_SETTEXTALIGN:
            case MR_SETTEXTCOLOR:
            case MR_SETBKCOLOR:
            case MR_OFFSETCLIPRGN:
            case MR_MOVETOEX:
            case MR_SETMETARGN:
            case MR_EXCLUDECLIPRECT:
            case MR_INTERSECTCLIPRECT:
            case MR_SCALEVIEWPORTEXTEX:
            case MR_SCALEWINDOWEXTEX:
            case MR_SAVEDC:
            case MR_RESTOREDC:
            case MR_SETWORLDTRANSFORM:
            case MR_MODIFYWORLDTRANSFORM:
            case MR_SELECTOBJECT:
            case MR_CREATEPEN:
            case MR_CREATEBRUSHINDIRECT:
            case MR_DELETEOBJECT:
            case MR_SELECTPALETTE:
            case MR_CREATEPALETTE:
            case MR_SETPALETTEENTRIES:
            case MR_RESIZEPALETTE:
            case MR_REALIZEPALETTE:
            case MR_SETARCDIRECTION:
            case MR_SETMITERLIMIT:
            case MR_BEGINPATH:
            case MR_ENDPATH:
            case MR_CLOSEFIGURE:
            case MR_SELECTCLIPPATH:
            case MR_ABORTPATH:
            case MR_EXTCREATEFONTINDIRECTW:
            case MR_CREATEMONOBRUSH:
            case MR_CREATEDIBPATTERNBRUSHPT:
            case MR_EXTCREATEPEN:
                goto PlayRec;
            default:
                break;
        } //switch

        if (iCnt == ((PLAYINFO *) lpData)->iRecord) {
PlayRec:
            bSuccess = PlayEnhMetaFileRecord(hDC, lpHandleTable,
                                             lpEnhMetaRecord, nHandles);
            wsprintf((LPSTR) ach, "%s", rgMetaName[lpEnhMetaRecord->iType]);
            for (i=0; i < lNumDword; i++) {
                wsprintf((LPSTR) achTmp, "%ld ", lpEnhMetaRecord->dParm[i]);
                if ((strlen(ach)+strlen(achTmp))/sizeof(char) >= 128)
                    break;
                strcat(ach, achTmp);
            }
            SetWindowText(ghTextWnd, ach);
        }
    }

    if (iCnt == ((PLAYINFO *) lpData)->iRecord) {
        iCnt = 0;
        return FALSE;
    }
    return bSuccess;
}

/******************************Public*Routine******************************\
*
* LoadBitmapFile
*
* Effects:  Loads the bitmap from file and return the bitmap
*
* Warnings: pszFileName contains the full path
*
* History:
*  18-Feb-1993 Petrus Wong           fix metaf bnp color problem
*  21-Oct-1992 Petrus Wong           fix data-misalignment
*  13-May-1992 Petrus Wong           return bitmap handle
*  09-Jan-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

HBITMAP hBmpLoadBitmapFile(HDC hDC, PSTR pszFileName)
{
    HANDLE              hFile, hMapFile;
    LPVOID              pMapFile, pMapFileTmp;
    LPBITMAPINFOHEADER  pbmh;
    LPBITMAPINFO        pbmi;
    PBYTE               pjTmp;
    ULONG               sizBMI;
    HBITMAP             hBitmap;
    INT                 iNumClr;
    BOOL                bCoreHdr;
    WORD                wBitCount;
    PFILEINFO           pFileInfo;

    hBitmap = NULL;

    if ((hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
            OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL)) == (HANDLE)-1) {
        SetWindowText(ghTextWnd, "Fail in file open");
        goto ErrExit1;
    }

    //
    // Create a map file of the opened file
    //
    if ((hMapFile = CreateFileMapping(hFile, NULL,
                             PAGE_READONLY, 0, 0, NULL)) == (HANDLE)-1) {
        SetWindowText(ghTextWnd, "Fail in creating map file");
        goto ErrExit2;

    }

    //
    // Map a view of the whole file
    //
    if ((pMapFile = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0)) == NULL) {
        SetWindowText(ghTextWnd, "Fail in mapping view of the Map File object");
        goto ErrExit3;
    }

    pMapFileTmp = pMapFile;

    //
    // First check that it is a bitmap file
    //
    if (*((PWORD)pMapFile) != 0x4d42) {              // 'BM'
        MessageBox(ghwndMain, "This is not a DIB bitmap file!", "Error", MB_OK);
        goto ErrExit3;
    }

    //
    // The file header doesn't end on DWORD boundary...
    //
    pbmh = (LPBITMAPINFOHEADER)((PBYTE)pMapFile + sizeof(BITMAPFILEHEADER));

    {
        BITMAPCOREHEADER bmch, *pbmch;
        BITMAPINFOHEADER bmih, *pbmih;
        PBYTE            pjTmp;
        ULONG            ulSiz;

        pbmch = &bmch;
        pbmih = &bmih;

        pjTmp = (PBYTE)pbmh;
        ulSiz = sizeof(BITMAPCOREHEADER);
        while (ulSiz--) {
            *(((PBYTE)pbmch)++) = *(((PBYTE)pjTmp)++);
        }

        pjTmp = (PBYTE)pbmh;
        ulSiz = sizeof(BITMAPINFOHEADER);
        while (ulSiz--) {
            *(((PBYTE)pbmih)++) = *(((PBYTE)pjTmp)++);
        }

        //
        // Use the size to determine if it is a BitmapCoreHeader or
        // BitmapInfoHeader
        //
        // Does PM supports 16 and 32 bpp? How?
        //
        if (bmch.bcSize == sizeof(BITMAPCOREHEADER))
        {
            wBitCount = bmch.bcBitCount;
            iNumClr = ((wBitCount == 24) ? 0 : (1 << wBitCount));
            sizBMI = sizeof(BITMAPCOREHEADER)+sizeof(RGBTRIPLE)*iNumClr;
            bCoreHdr = TRUE;
        }
        else            // BITMAPINFOHEADER
        {
            wBitCount = bmih.biBitCount;
            switch (wBitCount) {
                case 16:
                case 32:
                    sizBMI = sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3;
                    break;
                case 24:
                    sizBMI = sizeof(BITMAPINFOHEADER);
                    break;
                default:
                    iNumClr = (1 << wBitCount);
                    sizBMI = sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*iNumClr;
                    break;
            }
            bCoreHdr = FALSE;
        }
    }

    if ((pbmi = (LPBITMAPINFO) LocalAlloc(LMEM_FIXED,sizBMI)) == NULL) {
        MessageBox(ghwndMain, "Fail in Memory Allocation!", "Error", MB_OK);
        goto ErrExit3;
    }

    //
    // Make sure we pass in a DWORD aligned BitmapInfo to CreateDIBitmap
    // Otherwise, exception on the MIPS platform
    // CR!!!  Equivalent to memcpy
    //
    pjTmp = (PBYTE)pbmi;

    while(sizBMI--)
    {
        *(((PBYTE)pjTmp)++) = *(((PBYTE)pbmh)++);
    }

    pMapFile = (PBYTE)pMapFile + ((BITMAPFILEHEADER *)pMapFile)->bfOffBits;

// !!! Use CreateBitmap for monochrome bitmap?

    //
    // Select the palette into the DC first before CreateDIBitmap()
    //
    bSelectDIBPal(hDC, pbmi, bCoreHdr);

// !!! We always pass a screen DC to this routine.
// !!! Maybe we should pass a metafile DC to this routine too.
// !!! The bitmap handle created for the screen DC won't give correct
// !!! color for the metafile DC.  So now, we always use the original
// !!! DIB info.
    if ((hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)pbmi,
                        CBM_INIT, pMapFile, pbmi, DIB_RGB_COLORS)) == NULL) {
        SetWindowText(ghTextWnd, "Fail in creating DIB bitmap from file!");
        goto ErrExit4;
    }

    // reset gbUseDIB flag, now that we have opened up a new DIB
    gbUseDIB = FALSE;

// !!! Always use the DIB info o.w. metafile DC don't get the right color.
#if 0
    if (GetDeviceCaps(hDC, BITSPIXEL) < wBitCount) {
#endif
        gbUseDIB = TRUE;
        bFreeDibFile(&gDib);
        pFileInfo = &(gDib.rgFileInfo[0]);
        pFileInfo->hFile        = hFile;
        pFileInfo->hMapFile     = hMapFile;
        pFileInfo->lpvMapView   = pMapFileTmp;

        gDib.rgpjFrame[0]       = pMapFile;
        gDib.rgpbmi[0]          = pbmi;
        gDib.rgbCoreHdr[0]      = bCoreHdr;
        gDib.ulFrames           =
        gDib.ulFiles            = 1;
        return (hBitmap);
#if 0
    }
#endif

ErrExit4:
    LocalFree(pbmi);
ErrExit3:
    CloseHandle(hMapFile);
ErrExit2:
    CloseHandle(hFile);
ErrExit1:

    return (hBitmap);

}


/******************************Public*Routine******************************\
*
* bFreeDibFile
*
* Effects:
*
* Warnings:
*
* History:
*  09-Feb-1993 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

BOOL bFreeDibFile(PDIBDATA pDibData)
{
    ULONG               ulFiles;
    ULONG               ulFrames;
    ULONG               i;
    PFILEINFO           pFileInfo;

    ulFiles = pDibData->ulFiles;
    ulFrames = pDibData->ulFrames;

    for (i = 0; i < ulFrames; i++) {
        LocalFree(pDibData->rgpjFrame[i]);
        LocalFree(pDibData->rgpbmi[i]);
    }

    for (i = 0; i < ulFiles; i++) {
        pFileInfo = &(pDibData->rgFileInfo[i]);
        CloseHandle(pFileInfo->hFile);
        CloseHandle(pFileInfo->hMapFile);
        UnmapViewOfFile(pFileInfo->lpvMapView);
    }

    pDibData->ulFiles = 0;
    pDibData->ulFrames = 0;
    return TRUE;
}




/******************************Public*Routine******************************\
*
* bGetBMP
*
* Effects: call common dialog and pass the filename to hBmpLoadBitmapFile
*          return TRUE if successful, FALSE otherwise
*
* Warnings:
*
* History:
*  13-May-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

BOOL bGetBMP(HWND hwnd, BOOL bMask) {
    OPENFILENAME    ofn;
    char            szFile[256], szFileTitle[256];
    static char     *szFilter;
    BOOL            bSuccess;
    HDC             hDC;

    bSuccess = FALSE;

    szFilter =
      "DIB files (*.bmp)\0*.bmp\0RLE files (*.rle)\0*.rle\0\0";

    strcpy(szFile, "*.bmp\0");
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFilter = szFilter;
    ofn.lpstrCustomFilter = (LPSTR) NULL;
    ofn.nMaxCustFilter = 0L;
    ofn.nFilterIndex = 1;
    ofn.lpstrFile = szFile;
    ofn.nMaxFile = sizeof(szFile);
    ofn.lpstrFileTitle = szFileTitle;
    ofn.nMaxFileTitle = sizeof(szFileTitle);
    ofn.lpstrInitialDir = NULL;
    ofn.lpstrTitle = (bMask ? "Load Mask" : "Load Bitmap");
    ofn.Flags = 0L;
    ofn.nFileOffset = 0;
    ofn.nFileExtension = 0;
    ofn.lpstrDefExt = "BMP";

    if (!GetOpenFileName(&ofn))
        return 0L;

    hDC = GetDC(ghwndDrawSurf);
    if (bMask) {
        ghBmpMask = hBmpLoadBitmapFile(hDC, szFile);
        if (ghBmpMask != NULL)
            bSuccess = TRUE;
    } else {
        ghBmp = hBmpLoadBitmapFile(hDC, szFile);
        if (ghBmp != NULL)
            bSuccess = TRUE;
    }
    ReleaseDC(ghwndDrawSurf, hDC);

    return bSuccess;
}

/******************************Public*Routine******************************\
*
* bHitTest
*
* Effects:  Enumerates metafile records
*           Calling bDoHitTest to process each record found.
*               The mouse position is passed to the bDoHitTest
*
* Warnings:
*
* History:
*  20-May-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

BOOL bHitTest(HDC hDC, INT x, INT y) {
    BOOL          bSuccess;
    ENHMETAHEADER EnhMetaHdr;
    RECT          rcClientDS;
    HTDATA        htData;
    static        HCURSOR hCurHT, hCurWait;

    bSuccess = TRUE;

    if (ghMetaf == 0)
        return 0L;

    hCurHT = LoadCursor(NULL, IDC_CROSS);
    hCurWait = LoadCursor(NULL, IDC_WAIT);

    GetEnhMetaFileHeader(ghMetaf, sizeof(EnhMetaHdr), &EnhMetaHdr);

    htData.point.x = x;
    htData.point.y = y;
    htData.iRecord = EnhMetaHdr.nRecords;

    SetCursor(hCurWait);
    if (gbFit2Wnd) {
        GetClientRect(ghwndDrawSurf, &rcClientDS);
        EnumEnhMetaFile(hDC, ghMetaf, (ENHMFENUMPROC)bDoHitTest, (LPVOID) &htData, (LPRECT)&rcClientDS);
    } else {
        RECT rc;

        rc.top = rc.left = 0;
        rc.right = EnhMetaHdr.rclBounds.right - EnhMetaHdr.rclBounds.left;
        rc.bottom = EnhMetaHdr.rclBounds.bottom - EnhMetaHdr.rclBounds.top;
        EnumEnhMetaFile(hDC, ghMetaf, (ENHMFENUMPROC)bDoHitTest, (LPVOID) &htData, (LPRECT)&rc);
    }
    SetCursor(hCurHT);

    return bSuccess;
}

/******************************Public*Routine******************************\
*
* bDoHitTest
*
* Effects:      Play all records related to transformation
*               Remember new mouse position if the record is a MoveTo
*               Convert rectangle, ellipse, lineto and bezier to path
*               Widen the path and convert it to region.
*               Test if the mouse position is inside the region.
*
* Warnings:     Only handle rectangle, ellipse, line and polybezier
*
* History:
*  20-May-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

BOOL APIENTRY bDoHitTest(HDC hDC, LPHANDLETABLE lpHandleTable,
                                  LPENHMETARECORD lpEnhMetaRecord,
                                  UINT nHandles,
                                  LPVOID lpData) {
    BOOL            bSuccess;
    char            ach[128];
    char            achTmp[128];
    POINT           PtOrg;
    LONG            lNumDword;
    XFORM           xfSave;
    SIZE            SizeWndEx, SizeViewEx;
    POINT           ptWndOrgin, ptViewOrgin;
    int             i, iMode;
    HRGN            hRgn;
    PPOINT          pPt, pPtTmp;
    static HGDIOBJ  hObjOld=NULL;
    static LONG     lCurX=0;
    static LONG     lCurY=0;
    static BOOL     bXform=FALSE;
    static int      iCnt=0;

    iCnt++;

    //
    // select a wide pen for widen path later on
    //
    hObjOld = SelectObject(hDC, ghpnWide);

    //
    // save the mouse hit position, this was passed in as a POINT structure
    //
    PtOrg.x = (((HTDATA *)lpData)->point).x;
    PtOrg.y = (((HTDATA *)lpData)->point).y;

    //
    // save the number of parameters for the GDI fcn concerned in DWORD.
    // This is the total size of metafile record in question less the
    // size of the GDI function
    //
    lNumDword = (lpEnhMetaRecord->nSize-8) / 4;

    switch (lpEnhMetaRecord->iType) {
    case MR_SETWINDOWEXTEX:
    case MR_SETWINDOWORGEX:
    case MR_SETVIEWPORTEXTEX:
    case MR_SETVIEWPORTORGEX:
    case MR_SETMAPMODE:
    case MR_SCALEVIEWPORTEXTEX:
    case MR_SCALEWINDOWEXTEX:
    case MR_SETMETARGN:
    case MR_SAVEDC:
    case MR_RESTOREDC:
    case MR_SETWORLDTRANSFORM:
    case MR_MODIFYWORLDTRANSFORM: {
        //
        // play all records related to transformation & font
        //
        PlayEnhMetaFileRecord(hDC, lpHandleTable,
                                   lpEnhMetaRecord, nHandles);
        bXform = TRUE;
        return TRUE;
    }
    //
    // convert the following GDI calls to path for hit testing
    //
    case MR_RECTANGLE: {
        BeginPath(hDC);
        Rectangle(hDC, lpEnhMetaRecord->dParm[0], lpEnhMetaRecord->dParm[1],
                       lpEnhMetaRecord->dParm[2], lpEnhMetaRecord->dParm[3]);
        EndPath(hDC);
        break;
    }
    case MR_ELLIPSE: {
        BeginPath(hDC);
        Ellipse(hDC, lpEnhMetaRecord->dParm[0], lpEnhMetaRecord->dParm[1],
                     lpEnhMetaRecord->dParm[2], lpEnhMetaRecord->dParm[3]);
        EndPath(hDC);
        break;
    }
    case MR_MOVETOEX: {
        //
        // Remember our current position
        //
        lCurX = lpEnhMetaRecord->dParm[0];
        lCurY = lpEnhMetaRecord->dParm[1];
        return TRUE;
    }
    case MR_LINETO: {
        BeginPath(hDC);
        MoveToEx(hDC, lCurX, lCurY, NULL);
        LineTo(hDC, lpEnhMetaRecord->dParm[0], lpEnhMetaRecord->dParm[1]);
        EndPath(hDC);
        break;
    }
    case MR_POLYBEZIER16: {
        int         i;
        LONG        lSize;
        LONG        lPtCnt;

        lPtCnt = lpEnhMetaRecord->dParm[4];
        lSize = lPtCnt * sizeof(POINTL);

        if ((pPt = (PPOINT) LocalAlloc(LMEM_FIXED, lSize)) == NULL) {
            SetWindowText(ghTextWnd, "ERROR: Failed in Memory Allocation: NO HIT");
            return TRUE;
        }

        pPtTmp = pPt;

        for (i=0; i < (INT) lPtCnt; i++, pPtTmp++) {
            pPtTmp->x = (LONG)(LOWORD(lpEnhMetaRecord->dParm[i+5]));
            pPtTmp->y = (LONG)(HIWORD(lpEnhMetaRecord->dParm[i+5]));
        }

        BeginPath(hDC);
        PolyBezier(hDC, (LPPOINT)pPt, (DWORD) lPtCnt);
        EndPath(hDC);
        LocalFree(pPt);
        break;
    }
    default:
        wsprintf((LPSTR) ach, "NO HIT: I don't Hit-Test %s", rgMetaName[lpEnhMetaRecord->iType]);
        SetWindowText(ghTextWnd, ach);
        return TRUE;
    }   //switch

    if (bXform) {
        //
        // Set World transform to identity temporarily so that pen width
        // is not affected by world to page transformation
        //
        GetWorldTransform(hDC, &xfSave);
        ModifyWorldTransform(hDC, NULL, MWT_IDENTITY);

        //
        // Set Page transform to identity temporarily so that pen width
        // is not affected by page to device transformation
        //
        iMode = GetMapMode(hDC);

        if ((iMode == MM_ISOTROPIC) || (iMode == MM_ANISOTROPIC)) {
            GetWindowOrgEx(hDC, &ptWndOrgin);
            GetWindowExtEx(hDC, &SizeWndEx);
            GetViewportExtEx(hDC, &SizeViewEx);
            GetViewportOrgEx(hDC, &ptViewOrgin);
        }

        SetMapMode(hDC, MM_TEXT);
    }

    WidenPath(hDC);

    hRgn = PathToRegion(hDC);

    if (hRgn == 0) {
        SetWindowText(ghTextWnd, "ERROR: Null Region: NO HIT");
        DeleteObject(hRgn);
        return TRUE;
    }
    //DPtoLP(hDC, &PtOrg, 1);
    //SetPixel(hDC, PtOrg.x, PtOrg.y, RGB(0, 255, 0));
    //
    // test if mouse hit position is in region
    //
    bSuccess = PtInRegion(hRgn, PtOrg.x, PtOrg.y);
    //Temporily comment this out
    FillRgn(hDC, hRgn, ghbrRed);
    DeleteObject(hRgn);
    //
    // Set transform back.
    //
    if (bXform) {
        SetWorldTransform(hDC, &xfSave);
        SetMapMode(hDC, iMode);

        if ((iMode == MM_ISOTROPIC) || (iMode == MM_ANISOTROPIC)) {
            SetWindowOrgEx(hDC, ptWndOrgin.x, ptWndOrgin.y, NULL);
            SetWindowExtEx(hDC, SizeWndEx.cx, SizeWndEx.cy, NULL);
            SetViewportExtEx(hDC, SizeViewEx.cx, SizeViewEx.cy, NULL);
            SetViewportOrgEx(hDC, ptViewOrgin.x, ptViewOrgin.y, NULL);
        }
    }

    if (bSuccess) {
        Beep(440, 500);
        //
        // Reporting the metafile record number.  Then reset counter.
        //
        SetDlgItemInt(ghwndCtrlPanel, DID_COUNTER, iCnt, FALSE);
        iCnt=0;
        wsprintf((LPSTR) ach, "HIT %s", rgMetaName[lpEnhMetaRecord->iType]);

        for (i=0; i < lNumDword; i++) {
            wsprintf((LPSTR) achTmp, "%ld ", lpEnhMetaRecord->dParm[i]);
            if ((strlen(ach)+strlen(achTmp))/sizeof(char) >= 128)
                break;
            strcat(ach, achTmp);
        }

        SetWindowText(ghTextWnd, ach);
        SelectObject(hDC, hObjOld);
        bXform = FALSE;
        return FALSE;
    }
    SetWindowText(ghTextWnd, "NO HIT");
    if (iCnt >= ((HTDATA *)lpData)->iRecord)
        iCnt = 0;
    return TRUE;

    UNREFERENCED_PARAMETER(lpHandleTable);
    UNREFERENCED_PARAMETER(nHandles);

}

/******************************Public*Routine******************************\
*
* bChooseNewFont
*
* Effects:
*
* Warnings:
*
* History:
*  20-May-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

BOOL bChooseNewFont(HWND hwnd, PLOGFONT plf, COLORREF *pClrRef) {
   HDC                  hDC;
   static CHOOSEFONT    chf;
   static BOOL          bInit=TRUE;


   if (bInit) {
        bInit = FALSE;

        hDC = GetDC( hwnd );
        chf.hDC = CreateCompatibleDC( hDC );
        ReleaseDC( hwnd, hDC );

        chf.lStructSize = sizeof(CHOOSEFONT);
        chf.hwndOwner = hwnd;
        chf.lpLogFont = plf;
        chf.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT;
        chf.rgbColors = *pClrRef;
        chf.lCustData = 0;
        chf.hInstance = (HANDLE)NULL;
        chf.lpszStyle = (LPSTR)NULL;
        chf.nFontType = SCREEN_FONTTYPE;
        chf.nSizeMin = 0;
        chf.nSizeMax = 0;
        chf.lpfnHook = (LPCFHOOKPROC)NULL;
        chf.lpTemplateName = (LPSTR)NULL;
   }

   if (ChooseFont( &chf ) == FALSE ) {
        DeleteDC( hDC );
	return FALSE;
   }

   *pClrRef = chf.rgbColors;

   DeleteDC( hDC );
   return (TRUE);
}

/******************************Public*Routine******************************\
*
* bChooseNewColor
*
* Effects:  Returns TRUE if successful; lpdwRGB points the color selected.
*           Otherwise, FALSE.
*
* Warnings:
*
* History:
*  21-May-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

BOOL bChooseNewColor(HWND hwnd, LPDWORD lpdwRGB) {
    static DWORD argbCust[16] = {
        RGB(255, 255, 255), RGB(255, 255, 255),
        RGB(255, 255, 255), RGB(255, 255, 255),
        RGB(255, 255, 255), RGB(255, 255, 255),
        RGB(255, 255, 255), RGB(255, 255, 255),
        RGB(255, 255, 255), RGB(255, 255, 255),
        RGB(255, 255, 255), RGB(255, 255, 255),
        RGB(255, 255, 255), RGB(255, 255, 255),
        RGB(255, 255, 255), RGB(255, 255, 255)
    };
    CHOOSECOLOR cc;
    BOOL bResult;

    cc.lStructSize = sizeof(CHOOSECOLOR);
    cc.hwndOwner = hwnd;
    cc.hInstance = ghModule;
    cc.rgbResult = *lpdwRGB;
    cc.lpCustColors = argbCust;
    cc.Flags = CC_RGBINIT | CC_SHOWHELP;
    cc.lCustData = 0;
    cc.lpfnHook = NULL;
    cc.lpTemplateName = NULL;

    bResult = ChooseColor(&cc);

    if (bResult) {
        *lpdwRGB = cc.rgbResult;
        return TRUE;
    }

    return FALSE;
}


/******************************Public*Routine******************************\
*
* hBrCreateBrush
*
* Effects: Creates a brush with the specified RGB
*
* Warnings:
*
* History:
*  04-Mar-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

HBRUSH hBrCreateBrush(HDC hDC, DWORD dwRGB)
{
    HDC hdcMem;
    HBRUSH hbr;
    HBRUSH hbrOld;
    HBITMAP hbmPat;
    HBITMAP hbmOld;

    hbr = CreateSolidBrush(dwRGB);
    hdcMem = CreateCompatibleDC(hDC);

    //
    // Minimum size for a bitmap to be used in a fill pattern is 8x8
    //
    hbmPat = CreateCompatibleBitmap(hDC, 8, 8);

    hbmOld = SelectObject(hdcMem, hbmPat);
    hbrOld = SelectObject(hdcMem, hbr);
    PatBlt(hdcMem, 0, 0, 8, 8, PATCOPY);

    //
    // Deselect hbmPat and hbr
    //
    SelectObject(hdcMem, hbmOld);
    SelectObject(hdcMem, hbrOld);

    DeleteDC(hdcMem);
    DeleteObject(hbr);

    hbr = CreatePatternBrush(hbmPat);

    DeleteObject(hbmPat);

    return hbr;
}


/******************************Public*Routine******************************\
*
* bPrintMf  Brings up the print dialog for printer setup and then
*           starts printing the enhanced metafile.
*
*           pPD     Points to a PRTDATA structure that contains the
*                   the handle for the Enh. Metafile for printing.
*
* Effects:  Returns TRUE if sucessful.  Otherwise, it is FALSE.
*           GlobalFree pPD when exits.
*
* Warnings:
*
* History:
*  22-Oct-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

BOOL bPrintMf(PPRTDATA pPD) {
    DOCINFO         DocInfo;
    HDC             hDCPrinter;
    ENHMETAHEADER   EnhMetaHdr;
    HENHMETAFILE    hEnhMf;
    TCHAR           buf[128];
    PRINTDLG        pd;
    BOOL            bSuccess;
    int             iEntries;
    PLOGPALETTE     plogPal;
    PBYTE           pjTmp;
    HPALETTE        hPal;


    bSuccess = TRUE;

    if (pPD->hMetaf == 0) {
        SetWindowText(ghTextWnd, "NO Metafile to print");
        goto PMF_EXIT;
        bSuccess = FALSE;
    }

    hEnhMf = CopyEnhMetaFile(pPD->hMetaf, NULL);
    pd.lStructSize = sizeof(PRINTDLG);
    pd.hwndOwner   = ghwndMain;
    pd.Flags       = PD_RETURNDC;
    pd.hInstance   = ghModule;

    if (!PrintDlg(&pd)) {
        SetWindowText(ghTextWnd, "Cancel Printing");
        goto PMF_EXIT;
        bSuccess = FALSE;
    }


    if (pd.hDC == NULL) {
        SetWindowText(ghTextWnd, "Failed in creating printer DC");
        goto PMF_EXIT;
        bSuccess = FALSE;
    }

    hDCPrinter = pd.hDC;
    GetEnhMetaFileDescription(hEnhMf, 128, (LPTSTR)buf);

    DocInfo.cbSize      = sizeof(DOCINFO);
    DocInfo.lpszDocName = (LPTSTR) buf;
    DocInfo.lpszOutput  = NULL;
    StartDoc(hDCPrinter, &DocInfo);
    StartPage(hDCPrinter);

    SetWindowText(ghTextWnd, "Printing...");

    iEntries = GetEnhMetaFilePaletteEntries(hEnhMf, 0, NULL);

    if (iEntries) {
        if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
                sizeof(DWORD) + sizeof(PALETTEENTRY)*iEntries )) == NULL) {
            MessageBox(ghwndMain, "Failed in Creating Palette!", "Error", MB_OK);
        }

        plogPal->palVersion = 0x300;
        plogPal->palNumEntries = (WORD) iEntries;
        pjTmp = (PBYTE) plogPal;
        pjTmp += 8;

        GetEnhMetaFilePaletteEntries(hEnhMf, iEntries, (PPALETTEENTRY)pjTmp);
        hPal = CreatePalette(plogPal);
        GlobalFree(plogPal);

        SelectPalette(hDCPrinter, hPal, FALSE);
        RealizePalette(hDCPrinter);
    }

    if (pPD->bFit2Wnd) {
        int     iWidth, iHeight;
        RECT    rc;

        iWidth = GetDeviceCaps(hDCPrinter, HORZRES);
        iHeight = GetDeviceCaps(hDCPrinter, VERTRES);
        rc.left = rc.top = 0;
        rc.right = iWidth;
        rc.bottom = iHeight;
        bSuccess = PlayEnhMetaFile(hDCPrinter, hEnhMf, (LPRECT) &rc);
        if (!bSuccess) {
            char    text[128];

            wsprintf(text, "Fail in PlayEnhMetaFile! Error %ld\n", GetLastError());
            OutputDebugString(text);
        }


    } else {
        GetEnhMetaFileHeader(hEnhMf, sizeof(ENHMETAHEADER), &EnhMetaHdr);
        {
        RECT rc;

        rc.top = rc.left = 0;
        rc.right = EnhMetaHdr.rclBounds.right - EnhMetaHdr.rclBounds.left;
        rc.bottom = EnhMetaHdr.rclBounds.bottom - EnhMetaHdr.rclBounds.top;
        bSuccess = PlayEnhMetaFile(hDCPrinter, hEnhMf, (LPRECT) &rc);
        if (!bSuccess) {
            char    text[128];

            wsprintf(text, "Fail in PlayEnhMetaFile! Error %ld\n", GetLastError());
            OutputDebugString(text);
        }

        }
    }

    EndPage(hDCPrinter);
    EndDoc(hDCPrinter);
    SetWindowText(ghTextWnd, "Printing Thread Done...");

PMF_EXIT:

    ExitThread(0);
    GlobalFree(pPD);
    return bSuccess;

}

/******************************Public*Routine******************************\
*
* bSelectDIBPal
*
* Effects: Creates a logical palette from the DIB and select it into the DC
*          and realize the palette. Saving the hPal in the ghPal
*
* Warnings: Based on Windows NT DIB support.  If PM support 16,24,32 bpp
*           we need to modify this routine.
*           Global alert! ghPal is changed here...
*
* History:
*  22-Jan-1993      Petrus Wong         PM support
*  31-Dec-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

BOOL bSelectDIBPal(HDC hDC, LPBITMAPINFO pbmi, BOOL bCoreHdr)
{
  LOGPALETTE    *plogPal;
  UINT          uiSizPal;
  INT           i, iNumClr;
  WORD          wBitCount;

  if (bCoreHdr) {
    wBitCount = ((LPBITMAPCOREINFO)pbmi)->bmciHeader.bcBitCount;
  } else {
    wBitCount = pbmi->bmiHeader.biBitCount;
  }

  switch (wBitCount) {
    case 16:
    case 24:
    case 32:                            // Does PM supports these?
        return FALSE;
    default:
        iNumClr = (1 << wBitCount);
        break;
  }

  uiSizPal = sizeof(WORD)*2 + sizeof(PALETTEENTRY)*iNumClr;
  if ((plogPal = (LOGPALETTE *) LocalAlloc(LMEM_FIXED,uiSizPal)) == NULL) {
      MessageBox(ghwndMain, "Fail in Allocating palette!", "Error", MB_OK);
      ghPal = NULL;
      return FALSE;
  }

  plogPal->palVersion = 0x300;
  plogPal->palNumEntries = (WORD) iNumClr;

  if (bCoreHdr) {
    for (i=0; i<iNumClr; i++) {
        plogPal->palPalEntry[i].peRed   = ((LPBITMAPCOREINFO)pbmi)->bmciColors[i].rgbtRed;
        plogPal->palPalEntry[i].peGreen = ((LPBITMAPCOREINFO)pbmi)->bmciColors[i].rgbtGreen;
        plogPal->palPalEntry[i].peBlue  = ((LPBITMAPCOREINFO)pbmi)->bmciColors[i].rgbtBlue;
        plogPal->palPalEntry[i].peFlags = PC_RESERVED;
    }
  } else {
    for (i=0; i<iNumClr; i++) {
        plogPal->palPalEntry[i].peRed   = pbmi->bmiColors[i].rgbRed;
        plogPal->palPalEntry[i].peGreen = pbmi->bmiColors[i].rgbGreen;
        plogPal->palPalEntry[i].peBlue  = pbmi->bmiColors[i].rgbBlue;
        plogPal->palPalEntry[i].peFlags = PC_RESERVED;
    }
  }

  DeleteObject(ghPal);
  ghPal = CreatePalette((LPLOGPALETTE)plogPal);
  if ((ghPal) == NULL) {
      MessageBox(ghwndMain, "Fail in creating palette!", "Error", MB_OK);
      return FALSE;
  }

  if ((GetDeviceCaps(hDC, RASTERCAPS)) & RC_PALETTE) {
    SelectPalette(hDC, ghPal, FALSE);
    RealizePalette(hDC);
  }

  GlobalFree(plogPal);

  return TRUE;
}


/******************************Public*Routine******************************\
*
* bPlgBlt
*
* Effects:  If Source DIB bpp > Destination DC's
*           use Halftone for PlgBlt.
*
* Warnings: Global Alert!
*           gbUseDIB is always TRUE now.
*
* History:
*  12-Mar-1993      Petrus Wong     fixed clr problem on playback (non-HT)
*  18-Feb-1993      Petrus Wong     fixed clr problem on playback (HT)
*  10-Feb-1993 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

BOOL bPlgBlt(HDC hDC, LPPOINT rgPtsBMP)
{
    HDC                  hDCRef;
    HDC                  hDCSrn;                // hDC can be metaf DC
    HGDIOBJ              hObjOld, hBmpMem;
    BITMAP               bm;
    INT                  iBpp;
    WORD                 wBitCnt;


    hDCSrn = GetDC(ghwndDrawSurf);
    hDCRef = CreateCompatibleDC(hDC);

    if (gbUseDIB) {
        int         cx, cy, dx, dy;
        PBITMAPINFO pbmi;

        pbmi = (gDib.rgpbmi[0]);
        dx = rgPtsBMP[0].x - rgPtsBMP[1].x;
        dy = rgPtsBMP[0].y - rgPtsBMP[1].y;
        cx = (INT) sqrt( dx * dx + dy * dy );

        dx = rgPtsBMP[0].x - rgPtsBMP[2].x;
        dy = rgPtsBMP[0].y - rgPtsBMP[2].y;
        cy = (INT) sqrt( dx * dx + dy * dy );

        iBpp = GetDeviceCaps(hDC, BITSPIXEL);

        if (gDib.rgbCoreHdr[0]) {
            wBitCnt = ((LPBITMAPCOREINFO)pbmi)->bmciHeader.bcBitCount;
        } else {
            wBitCnt = pbmi->bmiHeader.biBitCount;
        }

        if (iBpp < wBitCnt) {   // Do Halftone
            SetStretchBltMode(hDCRef, HALFTONE);
            if (ghHT) {
                SelectPalette(hDCRef, ghHT, FALSE);
                SelectPalette(hDC, ghHT, FALSE);
                SelectPalette(hDCSrn, ghHT, FALSE); // hDC can be metaf DC
                RealizePalette(hDCSrn);             // always realize the srn DC

                // Don't have to realize the palette in hDCRef
                // RealizePalette(hDCRef);

                // has to be compatible with screen DC, cannot be hDCRef
                // memory DC has no bitmap by default?
                // hDC may be a metafile DC, so use hDCSrn
                hBmpMem = CreateCompatibleBitmap(hDCSrn, cx, cy);
                SelectObject(hDCRef, hBmpMem);
            } else {
                MessageBox(ghwndMain, "Halftone palette is null!", "Error", MB_OK);
            }
        } else {
            SetStretchBltMode(hDCRef, COLORONCOLOR);
            if (ghPal) {
                if (ghDCMetaf == hDC)
                    CopyPalette(ghPal);
                SelectPalette(hDCRef, ghPal, FALSE);
                SelectPalette(hDC, ghPal, FALSE);
                SelectPalette(hDCSrn, ghPal, FALSE); // hDC can be metaf DC
                RealizePalette(hDCSrn);             // always realize the srn DC

                // Don't have to realize the palette in hDCRef
                // RealizePalette(hDCRef);

                // has to be compatible with screen DC, cannot be hDCRef
                // memory DC has no bitmap by default?
                // hDC may be a metafile DC, so use hDCSrn
                hBmpMem = CreateCompatibleBitmap(hDCSrn, cx, cy);
                SelectObject(hDCRef, hBmpMem);
            } else {
                MessageBox(ghwndMain, "Palette is null!", "Error", MB_OK);
            }
        }

        if (gDib.rgbCoreHdr[0]) {
            StretchDIBits(hDCRef, 0,0, cx, cy,
                          0,0, ((LPBITMAPCOREINFO)pbmi)->bmciHeader.bcWidth, ((LPBITMAPCOREINFO)pbmi)->bmciHeader.bcHeight,
                          gDib.rgpjFrame[0], pbmi, DIB_RGB_COLORS, SRCCOPY);
        } else {
            StretchDIBits(hDCRef, 0,0, cx, cy,
                          0,0, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight,
                          gDib.rgpjFrame[0], pbmi, DIB_RGB_COLORS, SRCCOPY);
        }

        PlgBlt(hDC, rgPtsBMP, hDCRef, 0, 0, cx, cy,
               ghBmpMask, 0, 0);

        DeleteObject(hBmpMem);

    } else {
        hObjOld = SelectObject(hDCRef, ghBmp);

        GetObject(ghBmpMask, sizeof(BITMAP), (LPSTR)&bm);
        if (bm.bmBitsPixel != 1) {
            SetWindowText(ghTextWnd, "ERROR: Mask has to be a Monochrome bitmap!");
            ghBmpMask = NULL;
        }

        GetObject(ghBmp, sizeof(BITMAP), (LPSTR)&bm);

        if (ghPal) {
            SelectPalette(hDC, ghPal, FALSE);
            RealizePalette(hDC);
            SetStretchBltMode(hDC, COLORONCOLOR);
        }
        PlgBlt(hDC, rgPtsBMP, hDCRef, 0, 0, bm.bmWidth, bm.bmHeight,
               ghBmpMask, 0, 0);

        SelectObject(hDCRef, hObjOld);
    }

    DeleteDC(hDCRef);
    ReleaseDC(ghwndDrawSurf, hDCSrn);
    return TRUE;

}



/******************************Public*Routine******************************\
*
* HPALETTE CopyPalette
*
* Effects:
*
* Warnings:
*
* History:
*  18-Sep-1992 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

HPALETTE CopyPalette(HPALETTE hPalSrc)
{
    PLOGPALETTE     plogPal;
    PBYTE           pjTmp;
    int             iNumEntries=0;
    HPALETTE        hPal;

    if ((iNumEntries = GetPaletteEntries(hPalSrc, 0, iNumEntries, NULL)) == 0) {
        MessageBox(ghwndMain, "No entry in palette to copy!", "Error", MB_OK);
        return (HPALETTE) NULL;
    }

    if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
            sizeof(DWORD) + sizeof(PALETTEENTRY)*iNumEntries )) == NULL) {
        MessageBox(ghwndMain, "Failed in CopyPalette!", "Error", MB_OK);
        return (HPALETTE) NULL;
    }

    plogPal->palVersion = 0x300;
    plogPal->palNumEntries = (WORD) iNumEntries;
    pjTmp = (PBYTE) plogPal;
    pjTmp += 8;
    GetPaletteEntries(hPalSrc, 0, iNumEntries, (PPALETTEENTRY)pjTmp);
    hPal = CreatePalette(plogPal);

    GlobalFree(plogPal);

    return hPal;
}




/******************************Public*Routine******************************\
*
* iTT
*
* Effects: set the global variable gbTT if the family is true type
*
* Warnings:
*
* History:
*  29-Apr-1993 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

int CALLBACK iTT(
    LPLOGFONT    lpLF,
    LPTEXTMETRIC lpTM,
    DWORD        dwFontType,
    LPARAM       lpData)
{

    if (lpTM->tmPitchAndFamily & TMPF_TRUETYPE) {
        //OutputDebugString("TRUETYPE\n");
        *((BOOL *)lpData) = TRUE;
    } else {
        //OutputDebugString("NON-TRUETYPE\n");
        *((BOOL *)lpData) = FALSE;
    }

#if 0
    //
    // that's equivalent
    //
    if (dwFontType & TRUETYPE_FONTTYPE) {
        //OutputDebugString("TRUETYPE\n");
        *((BOOL *)lpData) = TRUE;
    } else {
        //OutputDebugString("NON-TRUETYPE\n");
        *((BOOL *)lpData) = FALSE;
    }
#endif
    return 0;

    UNREFERENCED_PARAMETER (lpLF);
    //UNREFERENCED_PARAMETER (lpTM);
    UNREFERENCED_PARAMETER (dwFontType);

}



/******************************Public*Routine******************************\
*
* CMTMLTFMT *pLoadMltFmtFile(VOID)
*
* Effects:  Load either EPS or enh mf
*
* Warnings: CR! change this to load multiple def of picture
*
* History:
*  16-Aug-1993 -by- Petrus Wong
* Wrote it.
\**************************************************************************/

CMTMLTFMT *pLoadMltFmtFile(VOID)
{
    OPENFILENAME    ofn;
    char            szDirName[256];
    char            szFile[256], szFileTitle[256];
    static char     *szFilter;
    HANDLE          hFile, hMapFile;
    LPVOID          pMapFile;
    DWORD           dwFileSizeLow, dwFileSizeHigh;
    CMTMLTFMT       *pMfmt;

    pMfmt = (CMTMLTFMT*)NULL;

    szFilter =
      "EPS files (*.eps)\0*.eps\0Enhanced Metafiles (*.emf)\0*.emf\0\0";

    GetSystemDirectory((LPSTR) szDirName, 256);
    strcpy(szFile, "*.eps\0");
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = GetFocus();
    ofn.lpstrFilter = szFilter;
    ofn.lpstrCustomFilter = (LPSTR) NULL;
    ofn.nMaxCustFilter = 0L;
    ofn.nFilterIndex = 1;
    ofn.lpstrFile = szFile;
    ofn.nMaxFile = sizeof(szFile);
    ofn.lpstrFileTitle = szFileTitle;
    ofn.nMaxFileTitle = sizeof(szFileTitle);
    ofn.lpstrInitialDir = szDirName;
    ofn.lpstrTitle = (LPSTR) NULL;
    ofn.Flags = 0L;
    ofn.nFileOffset = 0;
    ofn.nFileExtension = 0;
    ofn.lpstrDefExt = "EPS";

    if (!GetOpenFileName(&ofn)) {
        goto EXIT;
    }

    if ((hFile = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ, NULL,
            OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL)) == (HANDLE)-1) {
        goto EXIT;
    }

    dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
    if ((dwFileSizeLow == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) {
        goto EXIT;
    }

    //
    // Create a map file of the opened file
    //
    if ((hMapFile = CreateFileMapping(hFile, NULL,
                             PAGE_READONLY, 0, 0, NULL)) == (HANDLE)-1) {
        goto EXIT2;
    }

    //
    // Map a view of the whole file
    //
    if ((pMapFile = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0)) == NULL) {
        goto EXIT3;
    }

//
// CR!! In future, change this to load different def of the picture...
//
  {
    ULONG       ulSize;
    PBYTE       pjTmp;
    RECTL       rectl;

    ulSize = dwFileSizeLow+sizeof(CMTMLTFMT);
    if ((pMfmt = (CMTMLTFMT *) LocalAlloc(LMEM_FIXED, ulSize)) == NULL) {
        MessageBox(GetFocus(), "Fail in Memory Allocation!", "Error", MB_OK);
        goto EXIT3;
    }

    pMfmt->ident = GDICOMMENT_IDENTIFIER;
    pMfmt->iComment = GDICOMMENT_MULTIFORMATS;
    pMfmt->nFormats = 1;
    pMfmt->aemrformat[0].cbData = dwFileSizeLow;
    pMfmt->aemrformat[0].offData = 11*sizeof(DWORD);

    // parse for %!PS-Adobe-3.0 EPSF keyword
    //           Enhanced Metafile signature
    // set EMRFORMAT.dSignature appropiately

    if (((ENHMETAHEADER *) pMapFile)->dSignature == ENHMETA_SIGNATURE) {

        pMfmt->aemrformat[0].dSignature = ENHMETA_SIGNATURE;
        pMfmt->aemrformat[0].nVersion = 0;                    // not for emf
        pMfmt->rclOutput.left   = ((ENHMETAHEADER *) pMapFile)->rclBounds.left;
        pMfmt->rclOutput.top    = ((ENHMETAHEADER *) pMapFile)->rclBounds.top;
        pMfmt->rclOutput.right  = ((ENHMETAHEADER *) pMapFile)->rclBounds.right;
        pMfmt->rclOutput.bottom = ((ENHMETAHEADER *) pMapFile)->rclBounds.bottom;
    }
    else    //assume it is Adobe EPS
    if (bGetEPSBounds(pMapFile, &rectl)) {

        char text[128];


        pMfmt->aemrformat[0].dSignature = 0x46535045;
        pMfmt->aemrformat[0].nVersion = 1;
        pMfmt->rclOutput.left   = rectl.left;
        pMfmt->rclOutput.top    = rectl.top;
        pMfmt->rclOutput.right  = rectl.right;
        pMfmt->rclOutput.bottom = rectl.bottom;

        wsprintf(text, "Bounds = %d %d %d %d",
                 rectl.left, rectl.top, rectl.right, rectl.bottom);
        MessageBox(GetFocus(), text, "Bounds", MB_OK);

    }
    else {
        // unknown file type
        Free(pMfmt);
        pMfmt = NULL;
        goto EXIT3;
    }

    pjTmp = (PBYTE)(((DWORD *)pMfmt->aemrformat)+4);
    while (dwFileSizeLow--) {
        *(((PBYTE)pjTmp)++) = *(((PBYTE)pMapFile)++);
    }

  }


EXIT3:
    CloseHandle(hMapFile);
EXIT2:
    CloseHandle(hFile);
EXIT:

    return pMfmt;
}


HLOCAL Free(CMTMLTFMT *pMfmt) {
    return LocalFree(pMfmt);
}

#define DBG 0

BOOL bIsAdobe(char *szStr)
{
    if (strcmp(szStr, "%!PS-Adobe-3.0") == 0)
        return TRUE;
    else
        return FALSE;
}

BOOL bIsEPS(char *szStr)
{
    if ((strcmp(szStr, "EPSF-3.0") == 0) ||
        (strcmp(szStr, "EPSF-2.0") == 0))
        return TRUE;
    else
        return FALSE;
}

BOOL bIsBndBox(char *szStr)
{
    if (strcmp(szStr, "%%BoundingBox:") == 0)
        return TRUE;
    else
        return FALSE;
}

BOOL bIsEOF(char *szStr)
{
    if (strcmp(szStr, "%%EOF") == 0)
        return TRUE;
    else
        return FALSE;
}


BOOL bGetEPSBounds(LPVOID lpData, RECTL *prctl)
{
    char szKeyWord[128], szValue[128];
    int  index;


    if (lpData == NULL) {
#if DBG
        MessageBox(GetFocus(), "Null Pointer!", "Error", MB_OK);
#endif
        return FALSE;
    }

    index = 0;

    if (!bGetWord(lpData, szKeyWord, &index))
        return FALSE;

    if (!bIsAdobe(szKeyWord)) {
        MessageBox(GetFocus(), "Not Adobe!", "Error", MB_OK);
        return FALSE;
    }

    if (!bGetWord(lpData, szValue, &index))
        return FALSE;

    if (!bIsEPS(szValue)) {
        MessageBox(GetFocus(), "Not EPS!", "Error", MB_OK);
        return FALSE;
    }

    if (!bGoNextLine(lpData, &index))
        return FALSE;

    while ((bGetWord(lpData, szKeyWord, &index)) &&
           (!bIsBndBox(szKeyWord))) {
#if DBG
        MessageBox(GetFocus(), "Skip to EOL", "Error", MB_OK);
#endif
        if (!bGoNextLine(lpData, &index)) {
            MessageBox(GetFocus(), "EOF unexpectedly!", "Error", MB_OK);
            return FALSE;
        }
    }

    if (bIsBndBox(szKeyWord)) {
        if (bGetWord(lpData, szValue, &index))
            prctl->left    = atol(szValue);
        else {
            MessageBox(GetFocus(), "Fail to get bnd: left!", "Error", MB_OK);
            return FALSE;
        }

        if (bGetWord(lpData, szValue, &index))
            prctl->top     = atol(szValue);
        else {
            MessageBox(GetFocus(), "Fail to get bnd: top!", "Error", MB_OK);
            return FALSE;
        }

        if (bGetWord(lpData, szValue, &index))
            prctl->right   = atol(szValue);
        else {
            MessageBox(GetFocus(), "Fail to get bnd: right!", "Error", MB_OK);
            return FALSE;
        }

        if (bGetWord(lpData, szValue, &index))
            prctl->bottom  = atol(szValue);
        else {
            MessageBox(GetFocus(), "Fail to get bnd: bottom", "Error", MB_OK);
            return FALSE;
        }
    }

    return TRUE;

}


BOOL bGetWord(LPVOID lpData, char *str, int* pi)
{
    char *pstr;

    pstr = str;

    while (((char *)lpData)[*pi] == ' ')
        (*pi)++;

    while ((((char *)lpData)[*pi] != ' ') &&
           (((char *)lpData)[*pi] != '\n') &&
           (((char *)lpData)[*pi] != '\r')) {
        *str++ = ((char *)lpData)[(*pi)++];
    }
    *str++ = '\0';

#if DBG
    {
    char text[128];

    wsprintf(text, "bGetWord gets %s", pstr);
    MessageBox(GetFocus(), text, "Info", MB_OK);
    }
#endif

    return TRUE;
}


BOOL bGoNextLine(LPVOID lpData, int* pi)
{
    char tmp[128];
    int  q;

    while ((((char *)lpData)[*pi] != '\n') &&
           (((char *)lpData)[*pi] != '\r'))
        (*pi)++;

    //
    // skip them
    //
    *pi += 2;

    q = *pi;

    if ((bGetWord(lpData, tmp, &q)) && (bIsEOF(tmp)) )
        return FALSE;

    return TRUE;
}
