MFEDIT.C

/******************************Module*Header*******************************\ 
* Module Name: mfedit.c
*
* Main module for the Enhanced Metafile Editor
* contains everything
*
* Copyright 1992 - 1998 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
*
*
\**************************************************************************/
#include "precomp.h"


/******************************Public*Routine******************************\
*
* FUNCTION: PolyDraw95(HDC, LPPOINT, LPBYTE, int)
*
* PURPOSE: Draws the points returned from a call to GetPath()
* to an HDC
*
* NOTES: This function is similar to the Windows NT PolyDraw
* function, which draws a set of line segments and Bezier
* curves. Because PolyDraw is not supported in Windows 95
* this PolyDraw95 function is used instead.
*
\**************************************************************************/

BOOL PolyDraw95(HDC hdc, // handle of a device context
CONST LPPOINT lppt, // array of points
CONST LPBYTE lpbTypes, // line and curve identifiers
int cCount) // count of points
{
int i;

for (i=0; i<cCount; i++)
switch (lpbTypes[i]) {
case PT_MOVETO :
MoveToEx(hdc, lppt[i].x, lppt[i].y, NULL);
break;

case PT_LINETO | PT_CLOSEFIGURE:
case PT_LINETO :
LineTo(hdc, lppt[i].x, lppt[i].y);
break;

case PT_BEZIERTO | PT_CLOSEFIGURE:
case PT_BEZIERTO :
PolyBezierTo(hdc, &lppt[i], 3);
i+=2;
break;
}

return TRUE;
}


/**************************************************************************\
*
* vErrOut
*
* Effects: Put up a message box with the error string and error code
* returned.
*
\**************************************************************************/

void vErrOut(char errstring[MAX_ERR_STRING])
{
DWORD dwError, dwThrdId;
char str[MAX_ERR_STRING];


if (gbDebug) {
dwError = GetLastError();
dwThrdId = GetCurrentThreadId();
wsprintf((LPSTR) str, "%s, tid = %lx, Error code = %d\n",
errstring, dwThrdId, dwError);
OutputDebugString((LPCTSTR)str);
//MessageBox(GetFocus(), (LPSTR)str, "MfEdit Error", MB_OK);
}
}


/**************************************************************************\
*
* FlushPalette
*
\**************************************************************************/

static void
FlushPalette(HDC hdc, int nColors)
{
LOGPALETTE *pPal;
HPALETTE hpal, hpalOld;
int i;

if (nColors == 256)
{
pPal = (LOGPALETTE *) LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT,
sizeof(LOGPALETTE) + (nColors-1) * sizeof(PALETTEENTRY));

if (pPal)
{
pPal->palVersion = 0x300;
pPal->palNumEntries = nColors;

// Mark everything PC_NOCOLLAPSE and PC_RESERVED to force every thing
// into the palette. Colors are already black because we zero initialized
// during memory allocation.

for (i = 0; i < nColors; i++)
{
pPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE | PC_RESERVED;
}

hpal = CreatePalette(pPal);
LocalFree(pPal);

hpalOld = SelectPalette(hdc, hpal, FALSE);
RealizePalette(hdc);

SelectPalette(hdc, hpalOld, FALSE);
DeleteObject(hpal);
}
}
}


/**************************************************************************\
*
* UpdateStaticMapping
*
\**************************************************************************/

static void
UpdateStaticMapping(PALETTEENTRY *pe332Palette)
{
HPALETTE hpalStock;
int iStatic, i332;
int iMinDist, iDist;
int iDelta;
int iMinEntry;
PALETTEENTRY *peStatic, *pe332;

hpalStock = GetStockObject(DEFAULT_PALETTE);

// The system should always have one of these
//TKASSERT(hpalStock != NULL);
// Make sure there's the correct number of entries
//TKASSERT(GetPaletteEntries(hpalStock, 0, 0, NULL) == STATIC_COLORS);

// Get the current static colors
GetPaletteEntries(hpalStock, 0, STATIC_COLORS, apeDefaultPalEntry);

// Zero the flags in the static colors because they are used later
peStatic = apeDefaultPalEntry;
for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++)
{
peStatic->peFlags = 0;
peStatic++;
}

// Zero the flags in the incoming palette because they are used later
pe332 = pe332Palette;
for (i332 = 0; i332 < 256; i332++)
{
pe332->peFlags = 0;
pe332++;
}

// Try to match each static color exactly
// This saves time by avoiding the least-squares match for each
// exact match
peStatic = apeDefaultPalEntry;
for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++)
{
pe332 = pe332Palette;
for (i332 = 0; i332 < 256; i332++)
{
if (peStatic->peRed == pe332->peRed &&
peStatic->peGreen == pe332->peGreen &&
peStatic->peBlue == pe332->peBlue)
{
//TKASSERT(pe332->peFlags != COLOR_USED);

peStatic->peFlags = EXACT_MATCH;
pe332->peFlags = COLOR_USED;
aiDefaultOverride[iStatic] = i332;

break;
}

pe332++;
}

peStatic++;
}

// Match each static color as closely as possible to an entry
// in the 332 palette by minimized the square of the distance
peStatic = apeDefaultPalEntry;
for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++)
{
// Skip colors already matched exactly
if (peStatic->peFlags == EXACT_MATCH)
{
peStatic++;
continue;
}

iMinDist = MAX_COL_DIST+1;
#if DBG
iMinEntry = -1;
#endif

pe332 = pe332Palette;
for (i332 = 0; i332 < 256; i332++)
{
// Skip colors already used
if (pe332->peFlags == COLOR_USED)
{
pe332++;
continue;
}

// Compute Euclidean distance squared
iDelta = pe332->peRed-peStatic->peRed;
iDist = iDelta*iDelta;
iDelta = pe332->peGreen-peStatic->peGreen;
iDist += iDelta*iDelta;
iDelta = pe332->peBlue-peStatic->peBlue;
iDist += iDelta*iDelta;

if (iDist < iMinDist)
{
iMinDist = iDist;
iMinEntry = i332;
}

pe332++;
}

//TKASSERT(iMinEntry != -1);

// Remember the best match
aiDefaultOverride[iStatic] = iMinEntry;
pe332Palette[iMinEntry].peFlags = COLOR_USED;

peStatic++;
}

// Zero the flags in the static colors because they may have been
// set. We want them to be zero so the colors can be remapped
peStatic = apeDefaultPalEntry;
for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++)
{
peStatic->peFlags = 0;
peStatic++;
}

// Reset the 332 flags because we may have set them
pe332 = pe332Palette;
for (i332 = 0; i332 < 256; i332++)
{
pe332->peFlags = PC_NOCOLLAPSE;
pe332++;
}

#if 0
for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++)
{
PrintMessage("Static color %2d maps to %d\n",
iStatic, aiDefaultOverride[iStatic]);
}
#endif
}

#define SwapPalE(i,j) { \
PALETTEENTRY palE; \
palE = pPal->palPalEntry[i]; \
pPal->palPalEntry[i] = pPal->palPalEntry[j]; \
pPal->palPalEntry[j] = palE; }


/**************************************************************************\
*
* SaveStaticEntries
*
\**************************************************************************/

VOID SaveStaticEntries(HDC hDC)
{
int i;

if (gbSystemColorsInUse) {
for (i = COLOR_SCROLLBAR; i <= COLOR_BTNHIGHLIGHT; i++)
gacrSave[i - COLOR_SCROLLBAR] = GetSysColor(i);

gbStaticSaved = TRUE;
}
}

/**************************************************************************\
*
* UseStaticEntries
*
\**************************************************************************/

static VOID UseStaticEntries(HDC hdc)
{
SetSysColors(NUM_STATIC_COLORS, gaiStaticIndex, gacrBlackAndWhite);
gbSystemColorsInUse = TRUE;

PostMessage(HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0);
}

/**************************************************************************\
*
* hCreateRGBPalette
*
\**************************************************************************/

HPALETTE hCreateRGBPalette(HDC hDC, int index)
{
PIXELFORMATDESCRIPTOR pfd;
PLOGPALETTE pLogPal, pPal;
int nClr, i, n;
HPALETTE hPal;
BOOL bUseStaticClr;


if (DescribePixelFormat(hDC, index, sizeof(PIXELFORMATDESCRIPTOR), &pfd) == 0) {
return (HPALETTE)NULL;
}

bUseStaticClr = pfd.dwFlags & PFD_NEED_SYSTEM_PALETTE;

if (pfd.dwFlags & PFD_NEED_PALETTE) {
nClr = 1 << pfd.cColorBits;

if ((pLogPal = (PLOGPALETTE) LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
(nClr-1) * sizeof(PALETTEENTRY))) != NULL) {

pLogPal->palVersion = 0x300;
pLogPal->palNumEntries = nClr;

for (i = 0; i < nClr; i++) {
pLogPal->palPalEntry[i].peRed =
ComponentFromIndex(i, pfd.cRedBits, pfd.cRedShift);
pLogPal->palPalEntry[i].peGreen =
ComponentFromIndex(i, pfd.cGreenBits, pfd.cGreenShift);
pLogPal->palPalEntry[i].peBlue =
ComponentFromIndex(i, pfd.cBlueBits, pfd.cBlueShift);
pLogPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
}

if ( nClr == 256) {
if (bUseStaticClr) {
pLogPal->palPalEntry[0].peFlags = 0;
pLogPal->palPalEntry[255].peFlags = 0;

SaveStaticEntries(hDC);
SetSystemPaletteUse(hDC, SYSPAL_NOSTATIC);
} else {
if ((pfd.cRedBits == 3) && (pfd.cRedShift == 0) &&
(pfd.cGreenBits == 3) && (pfd.cGreenShift == 3) &&
(pfd.cBlueBits == 2) && (pfd.cBlueShift == 6)) {
UpdateStaticMapping(pLogPal->palPalEntry);

for (i = 0; i < 20; i++) {
pLogPal->palPalEntry[aiDefaultOverride[i]] =
apeDefaultPalEntry[i];
}

}
}
}

FlushPalette(hDC, nClr);

hPal = CreatePalette(pLogPal);
LocalFree(pLogPal);
SelectPalette(hDC, hPal, FALSE);
RealizePalette(hDC);


if (bUseStaticClr)
UseStaticEntries(hDC);

}
}
// set up logical indices for CI mode
else if( pfd.iPixelType == PFD_TYPE_COLORINDEX ) {
if (pfd.cColorBits == 4) {

// for 4-bit, create a logical palette with 16 entries

n = 16;
pPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
(n-1) * sizeof(PALETTEENTRY));
pPal->palVersion = 0x300;
pPal->palNumEntries = n;

for( i = 0; i < 8; i ++) {
pPal->palPalEntry[i] = apeDefaultPalEntry[i];
}
for (i = 8; i < 16; i++) {
pPal->palPalEntry[i] = apeDefaultPalEntry[i+4];
}

// conform expects indices 0..3 to be BLACK,RED,GREEN,BLUE, so
// we rearrange the table for now.

SwapPalE(1,9)
SwapPalE(2,10)
SwapPalE(3,12)

} else if (pfd.cColorBits == 8) {

// for 8-bit, create a logical palette with 256 entries, making
// sure that the 20 system colors exist in the palette

n = 256;
pPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
(n-1) * sizeof(PALETTEENTRY));
pPal->palVersion = 0x300;
pPal->palNumEntries = n;

hPal = GetStockObject (DEFAULT_PALETTE);

// start by copying default palette into new one

GetPaletteEntries( hPal, 0, 20, pPal->palPalEntry);

// conform expects indices 0..3 to be BLACK,RED,GREEN,BLUE, so
// we rearrange the table for now.

SwapPalE(1,13)
SwapPalE(2,14)
SwapPalE(3,16)

for( i = 20; i < n; i ++) {
pPal->palPalEntry[i].peRed = (BYTE) (i - 1);
pPal->palPalEntry[i].peGreen = (BYTE) (i - 2);
pPal->palPalEntry[i].peBlue = (BYTE) (i - 3);
pPal->palPalEntry[i].peFlags = (BYTE) 0;
}


// If we are taking possession of the system colors,
// must guarantee that 0 and 255 are black and white
// (respectively), so that they can remap to the
// remaining two static colors. All other entries must
// be marked as PC_NOCOLLAPSE.

if ( gbUseStaticColors )
{
pPal->palPalEntry[0].peRed =
pPal->palPalEntry[0].peGreen =
pPal->palPalEntry[0].peBlue = 0x00;

pPal->palPalEntry[255].peRed =
pPal->palPalEntry[255].peGreen =
pPal->palPalEntry[255].peBlue = 0xFF;

pPal->palPalEntry[0].peFlags =
pPal->palPalEntry[255].peFlags = 0;

for ( i = 1 ; i < 255 ; i++ )
{
pPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE;

// This is a workaround for a GDI palette "feature". If
// any of the static colors are repeated in the palette,
// those colors will map to the first occurance. So, for
// our case where there are only two static colors (black
// and white), if a white color appears anywhere in the
// palette other than in the last entry, the static white
// will remap to the first white. This destroys the nice
// one-to-one mapping we are trying to achieve.
//
// There are two ways to workaround this. The first is to
// simply not allow a pure white anywhere but in the last
// entry. Such requests are replaced with an attenuated
// white of (0xFE, 0xFE, 0xFE).
//
// The other way is to mark these extra whites with
// PC_RESERVED which will cause GDI to skip these entries
// when mapping colors. This way the app gets the actual
// colors requested, but can have side effects on other
// apps.

if ( pPal->palPalEntry[i].peRed == 0xFF &&
pPal->palPalEntry[i].peGreen == 0xFF &&
pPal->palPalEntry[i].peBlue == 0xFF )
{
pPal->palPalEntry[i].peFlags |= PC_RESERVED;
}
}

SaveStaticEntries(hDC);
SetSystemPaletteUse(hDC, SYSPAL_NOSTATIC);
}

} else {
// for pixel formats > 8 bits deep, create a logical palette with
// 4096 entries

n = 4096;
pPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
(n-1) * sizeof(PALETTEENTRY));
pPal->palVersion = 0x300;
pPal->palNumEntries = n;

for( i = 0; i < n; i ++) {
pPal->palPalEntry[i].peRed = (BYTE) ((i & 0x000f) << 4);
pPal->palPalEntry[i].peGreen = (BYTE) (i & 0x00f0);
pPal->palPalEntry[i].peBlue = (BYTE) ((i & 0x0f00) >> 4);
pPal->palPalEntry[i].peFlags = (BYTE) 0;
}

// conform expects indices 0..3 to be BLACK,RED,GREEN,BLUE, so
// we rearrange the table for now.

SwapPalE(1,0xf)
SwapPalE(2,0xf0)
SwapPalE(3,0xf00)
}

hPal = CreatePalette(pPal);
LocalFree(pPal);


FlushPalette(hDC, n);

SelectPalette(hDC, hPal, FALSE);
n = RealizePalette(hDC);

if ( gbUseStaticColors )
UseStaticEntries(hDC);
}

return hPal;
}

/******************************Public*Routine******************************\
*
* bSetupRC
*
* Effects: Sets up the OpenGL rendering context
*
* Warnings:
*
\**************************************************************************/

#ifdef OPENGL_EMF
BOOL bSetupRC(HDC hDC, PIXELFORMATDESCRIPTOR *ppfdIn)
{
PIXELFORMATDESCRIPTOR pfd, *ppfd;
INT iPfmt;
BOOL bRet=FALSE;
HPALETTE hPal=(HPALETTE)NULL;
HGLRC hRC;
char text[128];

if ((ppfdIn != (PIXELFORMATDESCRIPTOR*)NULL) && gbUseMfPFD) {
ppfd = ppfdIn;
} else {
ppfd = &pfd;
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion= 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cRedBits =
pfd.cRedShift =
pfd.cGreenBits =
pfd.cGreenShift =
pfd.cBlueBits =
pfd.cBlueShift =
pfd.cAlphaBits =
pfd.cAlphaShift = 0;
pfd.cAccumBits = 24;
pfd.cAccumRedBits =
pfd.cAccumGreenBits =
pfd.cAccumBlueBits =
pfd.cAccumAlphaBits = 0;
pfd.cDepthBits = 24;
pfd.cStencilBits = 24;
pfd.cAuxBuffers =
pfd.iLayerType =
pfd.bReserved = 0;
pfd.dwLayerMask = PFD_MAIN_PLANE;
pfd.dwVisibleMask = 0;
pfd.dwDamageMask = 0;
}

if ((iPfmt = ChoosePixelFormat(hDC, ppfd)) != 0) {
bRet = SetPixelFormat(hDC, iPfmt, ppfd);

gbDB = (ppfd->dwFlags & PFD_DOUBLEBUFFER) ? TRUE : FALSE;

if ((hPal = hCreateRGBPalette(hDC, iPfmt)) != (HPALETTE)NULL) {
SelectPalette(hDC, hPal, FALSE);
RealizePalette(hDC);
bRet = bRet && TRUE;
} else {
bRet = FALSE;
}

hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);

wsprintf(text, "bSetupRC: hDC=%lx, hRC=%lx", hDC, hRC);
vErrOut(text);

}
return bRet;
}

/**************************************************************************\
*
* bSetRC2MatchEmfRC
*
* Effects: If the bOpenGL flag is not set in the metafile header,
* return FALSE.
*
* If the bOpenGL flag is set, retrieve the pfd from the enhanced
* metafile, if exists. Set the pixel format with the retrieved
* pfd on the hDC. If the pfd is not recorded, let bSetupRC pick
* the pfd.
*
* If ppfd is not null, copy the pfd in the metafile record,
* to the ppfd. If ppfd->nSize == 0, that means the pfd is not
* found in the metafile record.
*
* Warnings:
*
* History:
* 05-May-1996
* Wrote it.
\**************************************************************************/

BOOL bSetRC2MatchEmfRC(HDC hDC,
ENHMETAHEADER EnhMetaHdr,
HENHMETAFILE hEnhMf,
PIXELFORMATDESCRIPTOR *ppfdIn)
{
BOOL bHasPFD = FALSE, bRCSet = FALSE;
char text[128];
PIXELFORMATDESCRIPTOR pfd;

if (EnhMetaHdr.bOpenGL) {

if (gpfnGetEnhMetaFilePixelFormat != (PROC)NULL) {

bHasPFD = ((gpfnGetEnhMetaFilePixelFormat)(hEnhMf,
sizeof(PIXELFORMATDESCRIPTOR),
&pfd) == 0) ? FALSE : TRUE;

bRCSet = bSetupRC(hDC, (bHasPFD ? &pfd : NULL));

wsprintf(text,
"bSetRC2MatchEmfRC: bRCSet=%ld, bHasPFD=%ld",
bRCSet, bHasPFD);
vErrOut(text);

} else {
vErrOut("bSetRC2MatchEmfRC: gpfnGetEnhMetaFilePixelFormat is NULL");
}

} else {
vErrOut("bSetRC2MatchEmfRC: EnhMetaHdr.bOpenGL is FALSE");
}

if (ppfdIn != (PIXELFORMATDESCRIPTOR*)NULL) {
if (bHasPFD) {
memcpy(ppfdIn, &pfd, sizeof(PIXELFORMATDESCRIPTOR));
} else {
ppfdIn->nSize = 0;
}
}

return bRCSet;
}


/******************************Public*Routine******************************\
*
* bCleanUpRC
*
* Effects: Cleans up the OpenGL rendering context
*
* Warnings:
*
\**************************************************************************/

BOOL bCleanUpRC(VOID)
{
HGLRC hRC;
HDC hDC;
char text[128];

hRC = wglGetCurrentContext();
hDC = wglGetCurrentDC();

wsprintf(text, "bCleanUpRC: hDC=%lx, hRC=%lx", hDC, hRC);
vErrOut(text);

wglMakeCurrent(hDC, NULL);
wglDeleteContext(hRC);
return TRUE;

}

#else
BOOL bSetupRC(HDC hDC, PIXELFORMATDESCRIPTOR *ppfdIn)
{
return TRUE;
}

BOOL bSetRC2MatchEmfRC(HDC hDC,
ENHMETAHEADER EnhMetaHdr,
HENHMETAFILE hEnhMf,
PIXELFORMATDESCRIPTOR *ppfd)
{
return TRUE;
}

BOOL bCleanUpRC(VOID)
{
return TRUE;
}
#endif

/**************************************************************************\
*
* WinMain
*
* Effects:
*
* Warnings:
*
* History:
* 06-May-1996 Retrieve the proc addr for GetEnhMetaFilePixelFormat.
* Wrote it.
\**************************************************************************/

int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
MSG msg;
HANDLE hAccel;
HMODULE hMod;

ghModule = GetModuleHandle(NULL);

//
// GDI32 may not support the OpenGL enhanced metafile (Win95 doesn't), in
// which case, the entry point doesn't exist, so we will do a GetProcAddress
// instead.
//
hMod = LoadLibrary("GDI32.DLL");
if (hMod != (HMODULE)NULL) {

gpfnGetEnhMetaFilePixelFormat =
GetProcAddress(hMod, "GetEnhMetaFilePixelFormat");

if (gpfnGetEnhMetaFilePixelFormat == (PROC)NULL)
vErrOut("Main: GetProcAddress(GetEnhMetaFilePixelFormat) failed");

} else {
vErrOut("Main: LoadLibrary(GDI32) failed");
}

if (!InitializeApp()) {
MessageBox(ghwndMain,
GetStringRes(IDS_INITAPPFAIL), GetStringRes(IDS_ERROR), MB_OK);
return 0;
}

if (!(hAccel = LoadAccelerators (ghModule, MAKEINTRESOURCE(ACCEL_ID))))
MessageBox(ghwndMain,
GetStringRes(IDS_LOADACCFAIL), GetStringRes(IDS_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
*
\***************************************************************************/

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,
GetStringRes(IDS_MFDEMOCL), GetStringRes2(IDS_EMF),
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;
}

/******************************Public*Routine******************************\
*
* lProcessWmCreate
*
* Effects: process WM_CREATE message
*
* Warnings:
*
\**************************************************************************/

LONG lProcessWmCreate(HWND hWnd)
{
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;
}


/******************************Public*Routine******************************\
*
* lProcessWmDrawClip
*
* Effects: process the WM_DRAWCLIPBOARD message
*
* Warnings:
*
\**************************************************************************/

LONG lProcessWmDrawClip(UINT message, DWORD wParam, LONG lParam)
{
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;
}

/******************************Public*Routine******************************\
*
* lProcessWmSize
*
* Effects: process the WM_SIZE message
*
* Warnings:
*
\**************************************************************************/

LRESULT lProcessWmSize(HWND hWnd, UINT message, DWORD wParam, LONG lParam)
{
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);

return DefWindowProc(hWnd, message, wParam, lParam);
}

/******************************Public*Routine******************************\
*
* lProcessWmDestroy
*
* Effects: process the WM_DESTROY message
*
* Warnings:
*
\**************************************************************************/

LONG lProcessWmDestroy(VOID)
{
if (ghDCMem != (HDC)NULL)
DeleteDC(ghDCMem);
if (ghMetaf != (HENHMETAFILE)NULL)
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;
}

/******************************Public*Routine******************************\
*
* lProcessDIDPlayStep
*
* Effects: process the WM_COMMAND DID_X messages
*
* Warnings:
*
\**************************************************************************/

LONG lProcessDIDPlayStep(DWORD wParam, INT *piPlus)
{
HDC hDCDrawSurf;
ENHMETAHEADER EnhMetaHdr;
RECT rcClientDS;
int iRecord;
PLAYINFO PlayInfo;
BOOL bRCSet = FALSE;

if (ghMetaf == 0)
return 0L;

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

if ((EnhMetaHdr.nRecords > 1) && (iRecord > 0) &&
(iRecord <= (INT) EnhMetaHdr.nRecords)) {
hDCDrawSurf = GetDC(ghwndDrawSurf);

bRCSet = bSetRC2MatchEmfRC(hDCDrawSurf, EnhMetaHdr, ghMetaf, NULL);
if (!bRCSet) {
vErrOut("lProcessDIDPlayStep failed");
}

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);
}

if (bRCSet) {
bCleanUpRC();
}

ReleaseDC(ghwndDrawSurf, hDCDrawSurf);
}
return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessDIDPlayTenPlus
*
* Effects: process the WM_COMMAND DID_TEN_PLUS message
*
* Warnings:
*
\**************************************************************************/

LONG lProcessDIDPlayTenPlus(INT *piPlus)
{
if (ghMetaf == 0)
return 0L;

*piPlus += 10;
SetDlgItemInt(ghwndCtrlPanel, DID_COUNTER, *piPlus, FALSE);
return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessMMCopy
*
* Effects: process the WM_COMMAND MM_COPY message
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMCopy(VOID)
{
if ((ghMetaf == 0) && (ghmf == 0)) {
SetWindowText(ghTextWnd, GetStringRes(IDS_NOMFFORCPY));
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, GetStringRes(IDS_CNVEMFTO3X));

if (!(uiSize = GetWinMetaFileBits(ghMetaf, 0, NULL, MM_ANISOTROPIC, hDCDrawSurf))) {
MessageBox(ghwndMain, GetStringRes(IDS_GETWMFBTSFAIL),
GetStringRes(IDS_ERROR), MB_OK);
goto COPY_3X_EXIT;
}

if ((pjData = (LPBYTE) LocalAlloc(LMEM_FIXED, uiSize)) == NULL) {
MessageBox(ghwndMain, GetStringRes(IDS_MALLOCFAIL),
GetStringRes(IDS_ERROR), MB_OK);
goto COPY_3X_EXIT;
}

if (!(uiSize = GetWinMetaFileBits(ghMetaf, uiSize, pjData, MM_ANISOTROPIC, hDCDrawSurf))) {
MessageBox(ghwndMain, GetStringRes(IDS_GETWMFBTSFAIL2),
GetStringRes(IDS_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, GetStringRes(IDS_MALLOCFAIL2));
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, GetStringRes(IDS_CPY3XMFTOCLP));
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, GetStringRes(IDS_GETMFBTSXFAIL),
GetStringRes(IDS_ERROR), MB_OK);
SetWindowText(ghTextWnd, GetStringRes(IDS_CNVFAIL));
goto COPY_EXIT;
}

if ((pvData = (LPVOID) LocalAlloc(LMEM_FIXED, uiSize)) == NULL) {
MessageBox(ghwndMain, GetStringRes(IDS_MALLOCFAIL),
GetStringRes(IDS_ERROR), MB_OK);
SetWindowText(ghTextWnd, GetStringRes(IDS_CNVFAIL));
goto COPY_EXIT;
}

if (!(uiSize = GetMetaFileBitsEx(ghmf, uiSize, pvData))) {
MessageBox(ghwndMain, GetStringRes(IDS_GETWMFBTSFAIL2X),
GetStringRes(IDS_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, GetStringRes(IDS_CNVFAIL));
goto COPY_EXIT;
}

}

//
// No Conversion required
//
{

HENHMETAFILE hEmfTmp;

hEmfTmp = CopyEnhMetaFile(ghMetaf, NULL);

if (hEmfTmp) {
SetWindowText(ghTextWnd, GetStringRes(IDS_CPYEMFTOCLP));
SetClipboardData(CF_ENHMETAFILE, hEmfTmp);
DeleteEnhMetaFile(hEmfTmp);
}

}

COPY_EXIT:

CloseClipboard();
return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessMMPaste
*
* Effects: process the WM_COMMAND MM_PASTE message
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMPaste(HWND hwnd, BOOL *pbReset)
{

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, GetStringRes(IDS_PST3XMF));
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, GetStringRes(IDS_NOINFO3XMFX));
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;

BuildFilterStrs(-1);
szFilter = BuildFilterStrs(IDS_FT_WMF);

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 = GetStringRes(IDS_SAVEMF);
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, GetStringRes(IDS_FILEOPNFAIL),
GetStringRes(IDS_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, GetStringRes(IDS_MAPFCREFAIL),
GetStringRes(IDS_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, GetStringRes(IDS_MAPVWMAPFOFAIL),
GetStringRes(IDS_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, GetStringRes(IDS_GET3XFRMCLPFAIL));
}

goto PASTE_EXIT;

}

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

hEmfTmp = GetClipboardData(CF_ENHMETAFILE);
if (hEmfTmp) {
SetWindowText(ghTextWnd, GetStringRes(IDS_PSTEMF));
if (ghMetaf != (HENHMETAFILE)NULL)
DeleteEnhMetaFile(ghMetaf);
ghMetaf = CopyEnhMetaFile(hEmfTmp, NULL);
DeleteEnhMetaFile(hEmfTmp);
GetEnhMetaFileHeader(ghMetaf, sizeof(EnhMetaHdr), &EnhMetaHdr);
SetDlgItemInt(ghwndCtrlPanel, DID_COUNTER, EnhMetaHdr.nRecords, FALSE);
*pbReset = TRUE;
} else {
SetWindowText(ghTextWnd, GetStringRes(IDS_GETEMFFROMCLPFAIL));
}
}
PASTE_EXIT:

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

/******************************Public*Routine******************************\
*
* lProcessMMDel
*
* Effects: process the WM_COMMAND MM_DEL message
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMDel(VOID)
{
OpenClipboard(ghwndMain);
EmptyClipboard();
CloseClipboard();
return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessMMPen
*
* Effects: process the WM_COMMAND MM_PEN message
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMPen(HWND hwnd)
{
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;
}

/******************************Public*Routine******************************\
*
* lProcessMMBrush
*
* Effects: process the WM_COMMAND MM_BRUSH message
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMBrush(HWND hwnd)
{
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;
}

/******************************Public*Routine******************************\
*
* lProcessMMFont
*
* Effects: process the WM_COMMAND MM_FONT message
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMFont(VOID)
{
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;
}

/******************************Public*Routine******************************\
*
* lProcessMMStrokeFill
*
* Effects: process the WM_COMMAND MM_TTOUTLN_STROKEFILL message
*
* Warnings:
*
* History:
* 03-Jan-1996 -by- Petrus Wong [PetrusW]
* Wrote it.
\**************************************************************************/

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

/******************************Public*Routine******************************\
*
* lProcessMMPolyDraw
*
* Effects: process the WM_COMMAND MM_TTOUTLN_POLYDRAW message
*
* Warnings:
*
\**************************************************************************/

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

/******************************Public*Routine******************************\
*
* lProcessMMMltfmts
*
* Effects: process the WM_COMMAND MM_C_MLTFMTS message
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMMltfmts(VOID)
{
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,
GetStringRes(IDS_LDMFMTFILEFAIL),
GetStringRes(IDS_ERROR),
MB_OK);
}

return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessMMHittest
*
* Effects: process the WM_COMMAND MM_HITTEST message
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMHittest(VOID)
{
static BOOL bHitTest=FALSE;
HWNDhwndRecBtn;

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, GetStringRes(IDS_NOMFLDFORHTST));
return 0L;
}
return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessMMLEAbout
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMLEAbout(VOID)
{
if (DialogBox(ghModule, (LPCSTR)"AboutBox", ghwndMain, (DLGPROC)About) == -1)
MessageBox(ghwndMain, GetStringRes(IDS_DLGABOUTCREFAIL),
GetStringRes(IDS_ERROR), MB_OK);
return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessMMAbout
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMAbout(VOID)
{
if (DialogBox(ghModule, "AboutBox", ghwndMain, (DLGPROC)About) == -1)
MessageBox(ghwndMain, GetStringRes(IDS_DLGABOUTCREFAIL),
GetStringRes(IDS_ERROR), MB_OK);
return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessMMLoadMaskBmp
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMLoadMaskBmp(HWND hwnd)
{
SetWindowText(ghTextWnd, GetStringRes(IDS_LDMSKBM));
bGetBMP(hwnd, TRUE);
return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessMMLoadBmp
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMLoadBmp(HWND hwnd)
{
SetWindowText(ghTextWnd, GetStringRes(IDS_LDBM));
bGetBMP(hwnd, FALSE);
return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessMMSaveBmp
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMSaveBmp(VOID)
{
SetWindowText(ghTextWnd, GetStringRes(IDS_SVDRAWSFASBM));
return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessDIDOpen
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessDIDOpen(HWND hwnd, CHAR *szLoadedMetaf, BOOL *pbReset)
{
ENHMETAHEADER EnhMetaHdr;
HENHMETAFILE hEmfTmp;

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

if (ghMetaf != (HENHMETAFILE)NULL)
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);
}
*pbReset = TRUE;
return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessMMRec
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMRec(HWND hwnd, CHAR *szFilename)
{
if (gbHitTest) {
SetWindowText(ghTextWnd, GetStringRes(IDS_MUSTESCHTSTMD));
return 0L;
}

SetWindowText(ghTextWnd, GetStringRes(IDS_REC));
if (!gbRecording) {
ghDCMetaf = hDCRecordMetafileAs(hwnd, szFilename);
}

if (ghDCMetaf == NULL) {
SetWindowText(ghTextWnd, GetStringRes(IDS_CREMFDCFAIL));
return 0L;
}

// Parse the szFilename for the title and GdiComment the metafile with it.
{
charszComment[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, GetStringRes(IDS_ADDCMNTFAIL),
GetStringRes(IDS_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;
}

/******************************Public*Routine******************************\
*
* lProcessDIDRec
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessDIDRec(HWND hwnd, INT *piMetafCnt, char *szFilename)
{
int iWidthMM, iHeightMM, iWidthPels, iHeightPels, iMMPerPelX, iMMPerPelY;
char szComment[256];
char szTitle[256];
RECT rc;
HDC hDC;


if (gbHitTest) {
SetWindowText(ghTextWnd, GetStringRes(IDS_MUSTESCHTSTMD));
return 0L;
}

SetWindowText(ghTextWnd, GetStringRes(IDS_REC));
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", *piMetafCnt);
*piMetafCnt++;
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 (gb3D)
bSetupRC(ghDCMetaf, NULL);
}

bSetAdvancedGraphics(ghDCMetaf);
}

if (ghDCMetaf == NULL) {
SetWindowText(ghTextWnd, GetStringRes(IDS_CREMFDCFAIL));
return 0L;
}
wsprintf((LPSTR) szComment, "MfEdit:\\0%s\\0\\0", szTitle);
#if 0
if (!GdiComment(ghDCMetaf, 256, szComment)) {
MessageBox(ghwndMain, GetStringRes(IDS_ADDCMNTFAIL),
GetStringRes(IDS_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;
}


/******************************Public*Routine******************************\
*
* lProcessDIDStop
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessDIDStop(VOID)
{
SetWindowText(ghTextWnd, GetStringRes(IDS_STOP));
if (gbRecording) {
if (gb3D && gbRCSet)
bCleanUpRC();
ghMetaf = CloseEnhMetaFile(ghDCMetaf);
gbRecording = FALSE;
}
return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessDIDPlay
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessDIDPlay(char *szLoadedMetaf)
{
HDC hDCDrawSurf;
ENHMETAHEADER EnhMetaHdr;
RECT rcClientDS;
int iEntries;
PLOGPALETTE plogPal;
PBYTE pjTmp;
HPALETTE hPal;
char szTmp[256];
BOOL bRCSet = FALSE;
#ifdef OPENGL_EMF
PIXELFORMATDESCRIPTOR pfd;
#endif
BOOL bHasPFD = TRUE;


wsprintf(szTmp, GetStringRes(IDS_FMT_PLAYMF), 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, GetStringRes(IDS_CREPALFAIL),
GetStringRes(IDS_ERROR), MB_OK);
}

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

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

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

#ifdef OPENGL_EMF
bRCSet = bSetRC2MatchEmfRC(hDCDrawSurf, EnhMetaHdr, ghMetaf, &pfd);
bHasPFD = (pfd.nSize != 0) ? TRUE : FALSE;
if (!bRCSet) {
vErrOut("lProcessDIDPlay (DspDC) failed");
}
#endif
if (gbFit2Wnd) {
GetClientRect(ghwndDrawSurf, &rcClientDS);
if (!PlayEnhMetaFile( hDCDrawSurf, ghMetaf, (LPRECT) &rcClientDS)) {
chartext[128];

wsprintf(text, GetStringRes(IDS_FMT_PLAYEMFFAIL), GetLastError());
OutputDebugString(text);
} else {
if (gbDB)
SwapBuffers(hDCDrawSurf);
}
} 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)) {
chartext[128];

wsprintf(text, GetStringRes(IDS_FMT_PLAYEMFFAIL), GetLastError());
OutputDebugString(text);
} else {
if (gbDB)
SwapBuffers(hDCDrawSurf);
}
}

if (bRCSet) {
bCleanUpRC();
bRCSet = FALSE;
}

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

#ifdef OPENGL_EMF
if (EnhMetaHdr.bOpenGL && !gbRCSet) {
char text[128];

bRCSet = bSetupRC(ghDCMetaf, (bHasPFD ? &pfd : NULL));
wsprintf(text,
"lProcessDIDPlay: (MetaDC) bRCSet=%ld, bHasPFD=%ld",
bRCSet, bHasPFD);
vErrOut(text);
}
#endif
{
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)) {
chartext[128];

wsprintf(text, GetStringRes(IDS_FMT_PLAYEMFFAIL), GetLastError());
OutputDebugString(text);
} else {
if (gbDB)
SwapBuffers(ghDCMetaf);
}


if (bRCSet) {
bCleanUpRC();
}

}
}

ReleaseDC(ghwndDrawSurf, hDCDrawSurf);
} else {
SetWindowText(ghTextWnd, GetStringRes(IDS_NOMFFORPLAY));
}

return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessDIDFf
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessDIDFf(BOOL *pbReset)
{
HDC hDCDrawSurf;
ENHMETAHEADER EnhMetaHdr;
RECT rcClientDS;
static int iRecord = 0;
PLAYINFO PlayInfo;
int iEntries;
PLOGPALETTE plogPal;
PBYTE pjTmp;
HPALETTE hPal;
static BOOL bInitRC = FALSE;
static BOOL bRCSet = FALSE;
BOOL bHasPFD = FALSE;

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, GetStringRes(IDS_CREPALFAIL),
GetStringRes(IDS_ERROR), MB_OK);
}

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

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

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

if (!bInitRC) {
bRCSet = bSetRC2MatchEmfRC(hDCDrawSurf, EnhMetaHdr, ghMetaf, NULL);
bInitRC = TRUE;
if (!bRCSet) {
vErrOut("lProcessDIDFf failed");
}
}

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) || *pbReset) {
iRecord = 0;
if (*pbReset)
SetDlgItemInt(ghwndCtrlPanel, DID_COUNTER, 0, FALSE);
*pbReset = FALSE;

if (bRCSet) {
bCleanUpRC();
bRCSet = FALSE;
}

bInitRC = FALSE;
}
return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessDIDClear
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessDIDClear(VOID)
{
HDC hDCDrawSurf;
HGDIOBJ hObjOld;
RECT rcDrawSurf;

SetWindowText(ghTextWnd, GetStringRes(IDS_DRAWSFCLR));
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;
}

/******************************Public*Routine******************************\
*
* lProcessMMImport3X
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMImport3X(VOID)
{
gbImport3X = (gbImport3X ? FALSE : TRUE);

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

/******************************Public*Routine******************************\
*
* lProcessMMExport3X
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMExport3X(VOID)
{
gbExport3X = (gbExport3X ? FALSE : TRUE);

if (gbExport3X)
CheckMenuItem(hMenu, MM_EXPORT_3X, MF_CHECKED);
else
CheckMenuItem(hMenu, MM_EXPORT_3X, MF_UNCHECKED);
return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessMMFit2Wnd
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMFit2Wnd(VOID)
{
gbFit2Wnd = (gbFit2Wnd ? FALSE : TRUE);

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

/******************************Public*Routine******************************\
*
* lProcessMMPrint
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessMMPrint(VOID)
{
DWORD dwThrdID;
HANDLE hThrd;
PPRTDATA pPrtData;

if (ghMetaf == 0) {
SetWindowText(ghTextWnd, GetStringRes(IDS_NOMFFORPRT));
return 0L;
}

//
// bPrintMf is supposed to free up the memory when done.
//
if ((pPrtData = (PPRTDATA) GlobalAlloc(GPTR, sizeof(PRTDATA))) == NULL) {
SetWindowText(ghTextWnd, GetStringRes(IDS_MALLOCFAIL2));
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, GetStringRes(IDS_CREPRTTHRDFAIL));
GlobalFree(pPrtData);
}

return 0L;
}

/******************************Public*Routine******************************\
*
* lProcessWmCommand
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG lProcessWmCommand(HWND hwnd,
UINT message,
DWORD wParam,
LONG lParam,
INT *piMetafCnt,
BOOL *pbReset,
char *szFilename,
char *szLoadedMetaf)
{
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:
return lProcessDIDPlayStep(wParam, &iPlus);

case DID_TEN_PLUS:
return lProcessDIDPlayTenPlus(&iPlus);

case MM_PAGESETUP:
case MM_CUT:
return 0L;

case MM_COPY:
return lProcessMMCopy();

case MM_PASTE:
return lProcessMMPaste(hwnd, pbReset);

case MM_DEL:
return lProcessMMDel();

case MM_PEN:
return lProcessMMPen(hwnd);

case MM_BRUSH:
return lProcessMMBrush(hwnd);

case MM_FONT:
return lProcessMMFont();

case MM_TTOUTLN_STROKEFILL:
return lProcessMMStrokeFill();

case MM_TTOUTLN_POLYDRAW:
return lProcessMMPolyDraw();

case MM_C_WND_MF:
return 0L;

case MM_C_BEGIN_GP:
case MM_C_END_GP:
return 0L;

case MM_C_MLTFMTS:
return lProcessMMMltfmts();

case MM_HITTEST:
return lProcessMMHittest();

case MM_LEABOUT:
return lProcessMMLEAbout();

case MM_ABOUT:
return lProcessMMAbout();

case MM_LOAD_MASKBMP:
return lProcessMMLoadMaskBmp(hwnd);

case MM_LOAD_BMP:
return lProcessMMLoadBmp(hwnd);

case MM_SAVE_BMP:
return lProcessMMSaveBmp();

case MM_LOAD:
case DID_OPEN:
return lProcessDIDOpen(hwnd, szLoadedMetaf, pbReset);

case MM_RECORD:
return lProcessMMRec(hwnd, szFilename);

case DID_RECORD:
return lProcessDIDRec(hwnd, piMetafCnt, szFilename);

case DID_STOP:
return lProcessDIDStop();

case DID_PLAY:
return lProcessDIDPlay(szLoadedMetaf);

case DID_FF:
return lProcessDIDFf(pbReset);

case DID_CLEAR:
return lProcessDIDClear();

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:
return lProcessMMImport3X();

case MM_EXPORT_3X:
return lProcessMMExport3X();

case MM_FIT2WND:
return lProcessMMFit2Wnd();

case MM_PRINT:
return lProcessMMPrint();

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

/***************************************************************************\
* MainWndProc
*
\***************************************************************************/

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: {
return lProcessWmCreate(hwnd);
}
case WM_DRAWCLIPBOARD: {
return lProcessWmDrawClip(message, wParam, lParam);
}
case WM_SIZE: {
return lProcessWmSize(hwnd, message, wParam, lParam);
}

case WM_DESTROY: {
return lProcessWmDestroy();
}
case WM_COMMAND: {
return lProcessWmCommand(hwnd,
message,
wParam,
lParam,
&iMetafCnt,
&bReset,
szFilename,
szLoadedMetaf);
}
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:
*
\**************************************************************************/

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;
static BOOL b3DSetup = FALSE;

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

hDC = GetDC(hwnd);

{
char text[128];

wsprintf(text, "DrawSurfWndProc: hDC=%lx", hDC);
vErrOut(text);
}

bSetAdvancedGraphics(hDC);

if (gb3D)
b3DSetup = bSetupRC(hDC, NULL);

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);
CreateCaret(hwnd, NULL, 1, CARET_HEIGHT);
#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);
}

//
// Apparently, at buttonup time, the mouse location is not clamped to
// the client area. So, the final ellipse or rectangle will be extended
// outside the client area.
//
// NextX = (SHORT) LOWORD(lParam);
// NextY = (SHORT) HIWORD(lParam);
NextX = PrevX;
NextY = PrevY;

// 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

#ifdef JAPAN
case WM_IME_REPORT:
if (IR_STRING == wParam) {
LPSTR lpsz, lpszMeta;

if (!(lpsz = lpszMeta = GlobalLock((HANDLE)lParam))) {
return FALSE;
}
hDC = GetDC(hwnd);
while(*lpsz) { // Draw all characters in the string
bDrawStuff(hDC, 0, 0, 0, 0, TRUE, FALSE, FALSE, lpsz);
IsDBCSLeadByte((BYTE)*lpsz) ? lpsz += 2 : ++lpsz;
}
ReleaseDC(hwnd, hDC);
if (gbRecording && (ghDCMetaf != NULL)) {
while(*lpszMeta) { // Draw all characters in the string
bDrawStuff(ghDCMetaf, 0, 0, 0, 0, TRUE, FALSE, FALSE, lpszMeta);
IsDBCSLeadByte((BYTE)*lpszMeta) ? lpszMeta += 2 : ++lpszMeta;
}
}
GlobalUnlock((HANDLE)lParam);
return TRUE;
}
return DefWindowProc(hwnd, message, wParam, lParam);
break;
#endif

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: {
HDC hDC;
HPALETTE hPal;

DestroyCaret();
DeleteObject(ghCurFont);

if (gb3D && b3DSetup) {
bCleanUpRC();
}

hDC = GetDC(hwnd);
hPal = SelectObject(hDC, GetStockObject(DEFAULT_PALETTE));
DeleteObject(hPal);
ReleaseDC(hwnd, hDC);

PostQuitMessage(0);
return 0L;
}

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


/***************************************************************************\
* About
*
* About dialog proc.
*
\***************************************************************************/

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.
*
\***************************************************************************/

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:
*
\**************************************************************************/

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.
*
\**************************************************************************/

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-CARET_HEIGHT);
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, IsDBCSLeadByte((BYTE)*lpstr) ? 2 : 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, GetStringRes(IDS_CREPNTFAIL),
GetStringRes(IDS_ERROR), MB_OK);
break;
}

if ((pjTypes = (PBYTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
sizeof(BYTE)*iNumPt )) == NULL) {
MessageBox(ghwndMain, GetStringRes(IDS_CREPBYTEFAIL),
GetStringRes(IDS_ERROR), MB_OK);
goto GP_EXIT1;
}

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

GP_EXIT1:
LocalFree(pPts);

}

} else {
TextOut(hDC, NextX, NextY, lpstr, IsDBCSLeadByte((BYTE)*lpstr) ? 2 : 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, Pt.y-CARET_HEIGHT);

}
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, GetStringRes(IDS_NOBMFOREMBED));
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;
static BOOL bRCSet = FALSE;


if (bErase || bMove)
return bSuccess;

if (ghMetaf == NULL) {
SetWindowText(ghTextWnd, GetStringRes(IDS_NOMFFOREMBED));
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, GetStringRes(IDS_CREPALFAIL),
GetStringRes(IDS_ERROR), MB_OK);
}

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

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

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

bRCSet = bSetRC2MatchEmfRC(hDC, EnhMetaHdr, ghMetaf, NULL);
if (!bRCSet) {
vErrOut("DID_METAF failed");
}

//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, GetStringRes(IDS_FMT_PLAYEMFFAIL), GetLastError());
OutputDebugString(text);
} else {
if (gbDB)
SwapBuffers(hDC);
}

}
ModifyWorldTransform(hDC, NULL, MWT_IDENTITY);

if (bRCSet) {
bCleanUpRC();
bRCSet = FALSE;
}

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, GetStringRes(IDS_CREPALFAIL),
GetStringRes(IDS_ERROR), MB_OK);
}

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

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

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

if (!bRCSet) {
bRCSet = bSetRC2MatchEmfRC(hDC, EnhMetaHdr, ghMetaf, NULL);
if (!bRCSet) {
vErrOut("DID_METAF failed");
}
}

//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, GetStringRes(IDS_FMT_PLAYEMFFAIL), GetLastError());
OutputDebugString(text);
} else {
if (gbDB)
SwapBuffers(hDC);
}

}
ModifyWorldTransform(hDC, NULL, MWT_IDENTITY);
iCntMF = 0; // reset
if (bRCSet) {
bCleanUpRC();
bRCSet = FALSE;
}
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:
*
\**************************************************************************/

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;

BuildFilterStrs(-1);
BuildFilterStrs(IDS_FT_EMF);
szFilter = BuildFilterStrs(IDS_FT_WMF);

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 = GetStringRes(IDS_LDMF);
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, GetStringRes(IDS_FMT_FILEOPNFAIL), GetLastError());
MessageBox(ghwndMain, text, GetStringRes(IDS_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, GetStringRes(IDS_FMT_CREMAPFILEFAIL), GetLastError());
MessageBox(ghwndMain, text, GetStringRes(IDS_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, GetStringRes(IDS_FMT_MAPVWMAPFOFAIL), GetLastError());
MessageBox(ghwndMain, text, GetStringRes(IDS_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, GetStringRes(IDS_ALDUSMF), "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, GetStringRes(IDS_FMT_SETWMFBTSFAIL), GetLastError());
MessageBox(ghwndMain, text, GetStringRes(IDS_ERROR), MB_OK);
}

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

wsprintf(text, GetStringRes(IDS_FMT_SETWMFBTSXFAIL), GetLastError());
MessageBox(ghwndMain, text, GetStringRes(IDS_ERROR), MB_OK);
}

// !!! Displaying the Windows format metafile
//if (!PlayMetaFile(hDCDrawSurf, ghmf)) {
// wsprintf(text, GetStringRes(IDS_FMT_PLAYMFFAIL), GetLastError());
// MessageBox(ghwndMain, text, GetStringRes(IDS_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, GetStringRes(IDS_FMT_GETMFFAIL), GetLastError());
MessageBox(ghwndMain, text, GetStringRes(IDS_ERROR), MB_OK);
bSuccess = FALSE;
goto ErrorExit3;
}

if (!(uiSize = GetMetaFileBitsEx(hmf, 0, NULL))) {
MessageBox(ghwndMain, GetStringRes(IDS_GETMFBTSXFAIL),
GetStringRes(IDS_ERROR), MB_OK);
return NULL;
}

if ((pvData = (LPVOID) LocalAlloc(LMEM_FIXED, uiSize)) == NULL) {
MessageBox(ghwndMain, GetStringRes(IDS_MALLOCFAIL),
GetStringRes(IDS_ERROR), MB_OK);
bSuccess = FALSE;
goto ErrorExit3;
}

if (!(uiSize = GetMetaFileBitsEx(hmf, uiSize, pvData))) {
MessageBox(ghwndMain, GetStringRes(IDS_GETMFBTSXFAIL2),
GetStringRes(IDS_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:
*
\**************************************************************************/

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;

BuildFilterStrs(-1);
szFilter = BuildFilterStrs(IDS_FT_EMF);
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 = GetStringRes(IDS_SAVEMFAS);
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 (gb3D)
gbRCSet = bSetupRC(hDCMeta, NULL);

bSetAdvancedGraphics(hDCMeta);
}

//
// parses the new filename, removes the extension and copy it into
// szFilename
//
strcpy(szFilename, "");
szTmp = (char *)My_mbstok(szFile, "\\");
strcpy(szTmp2, szTmp);
while (szTmp != NULL) {
szTmp = (char *)My_mbstok(NULL, "\\");
if (szTmp != NULL) {
strcat(szFilename, szTmp2);
strcpy(szTmp2, szTmp);
strcat(szFilename, "\\");
}
}
szTmp = (char *)My_mbstok(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:
*
\**************************************************************************/

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 EMR_SETWINDOWEXTEX:
case EMR_SETWINDOWORGEX:
case EMR_SETVIEWPORTEXTEX:
case EMR_SETVIEWPORTORGEX:
case EMR_SETBRUSHORGEX:
case EMR_SETMAPMODE:
case EMR_SETBKMODE:
case EMR_SETPOLYFILLMODE:
case EMR_SETROP2:
case EMR_SETSTRETCHBLTMODE:
case EMR_SETTEXTALIGN:
case EMR_SETTEXTCOLOR:
case EMR_SETBKCOLOR:
case EMR_OFFSETCLIPRGN:
case EMR_MOVETOEX:
case EMR_SETMETARGN:
case EMR_EXCLUDECLIPRECT:
case EMR_INTERSECTCLIPRECT:
case EMR_SCALEVIEWPORTEXTEX:
case EMR_SCALEWINDOWEXTEX:
case EMR_SAVEDC:
case EMR_RESTOREDC:
case EMR_SETWORLDTRANSFORM:
case EMR_MODIFYWORLDTRANSFORM:
case EMR_SELECTOBJECT:
case EMR_CREATEPEN:
case EMR_CREATEBRUSHINDIRECT:
case EMR_DELETEOBJECT:
case EMR_SELECTPALETTE:
case EMR_CREATEPALETTE:
case EMR_SETPALETTEENTRIES:
case EMR_RESIZEPALETTE:
case EMR_REALIZEPALETTE:
case EMR_SETARCDIRECTION:
case EMR_SETMITERLIMIT:
case EMR_BEGINPATH:
case EMR_ENDPATH:
case EMR_CLOSEFIGURE:
case EMR_SELECTCLIPPATH:
case EMR_ABORTPATH:
case EMR_EXTCREATEFONTINDIRECTW:
case EMR_CREATEMONOBRUSH:
case EMR_CREATEDIBPATTERNBRUSHPT:
case EMR_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;

if (gbDB)
SwapBuffers(hDC);

return FALSE;
}
return bSuccess;
}

/******************************Public*Routine******************************\
*
* LoadBitmapFile
*
* Effects: Loads the bitmap from file and return the bitmap
*
* Warnings: pszFileName contains the full path
*
\**************************************************************************/

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, GetStringRes(IDS_FILEOPNFAIL));
goto ErrExit1;
}

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

}

//
// Map a view of the whole file
//
if ((pMapFile = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0)) == NULL) {
SetWindowText(ghTextWnd, GetStringRes(IDS_MAPVWOFMAPFOFAIL));
goto ErrExit3;
}

pMapFileTmp = pMapFile;

//
// First check that it is a bitmap file
//
if (*((PWORD)pMapFile) != 0x4d42) { // 'BM'
MessageBox(ghwndMain, GetStringRes(IDS_NOTDIBBMFILE),
GetStringRes(IDS_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, GetStringRes(IDS_MALLOCFAIL),
GetStringRes(IDS_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:
*
\**************************************************************************/

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:
*
\**************************************************************************/

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

bSuccess = FALSE;

BuildFilterStrs(-1);
BuildFilterStrs(IDS_FT_DIB);
szFilter = BuildFilterStrs(IDS_FT_RLE);

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 ? GetStringRes(IDS_LDMSK) : "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:
*
\**************************************************************************/

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
*
\**************************************************************************/

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 EMR_SETWINDOWEXTEX:
case EMR_SETWINDOWORGEX:
case EMR_SETVIEWPORTEXTEX:
case EMR_SETVIEWPORTORGEX:
case EMR_SETMAPMODE:
case EMR_SCALEVIEWPORTEXTEX:
case EMR_SCALEWINDOWEXTEX:
case EMR_SETMETARGN:
case EMR_SAVEDC:
case EMR_RESTOREDC:
case EMR_SETWORLDTRANSFORM:
case EMR_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 EMR_RECTANGLE: {
BeginPath(hDC);
Rectangle(hDC, lpEnhMetaRecord->dParm[0], lpEnhMetaRecord->dParm[1],
lpEnhMetaRecord->dParm[2], lpEnhMetaRecord->dParm[3]);
EndPath(hDC);
break;
}
case EMR_ELLIPSE: {
BeginPath(hDC);
Ellipse(hDC, lpEnhMetaRecord->dParm[0], lpEnhMetaRecord->dParm[1],
lpEnhMetaRecord->dParm[2], lpEnhMetaRecord->dParm[3]);
EndPath(hDC);
break;
}
case EMR_MOVETOEX: {
//
// Remember our current position
//
lCurX = lpEnhMetaRecord->dParm[0];
lCurY = lpEnhMetaRecord->dParm[1];
return TRUE;
}
case EMR_LINETO: {
BeginPath(hDC);
MoveToEx(hDC, lCurX, lCurY, NULL);
LineTo(hDC, lpEnhMetaRecord->dParm[0], lpEnhMetaRecord->dParm[1]);
EndPath(hDC);
break;
}
case EMR_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, GetStringRes(IDS_MALLOCFAILNOHIT));
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, GetStringRes(IDS_FMT_NOHTST), 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, GetStringRes(IDS_NULLRGNHTSTFAIL));
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, GetStringRes(IDS_FMT_HIT), 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, GetStringRes(IDS_NOHIT));
if (iCnt >= ((HTDATA *)lpData)->iRecord)
iCnt = 0;
return TRUE;

UNREFERENCED_PARAMETER(lpHandleTable);
UNREFERENCED_PARAMETER(nHandles);

}

/******************************Public*Routine******************************\
*
* bChooseNewFont
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

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:
*
\**************************************************************************/

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:
*
\**************************************************************************/

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:
*
\**************************************************************************/

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;
BOOL bRCSet = FALSE;


bSuccess = TRUE;

if (pPD->hMetaf == 0) {
SetWindowText(ghTextWnd, GetStringRes(IDS_NOMFTOPRT));
goto PMF_EXIT;
bSuccess = FALSE;
}

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

if (!PrintDlg(&pd)) {
SetWindowText(ghTextWnd, GetStringRes(IDS_ESCPRT));
goto PMF_EXIT;
bSuccess = FALSE;
}

if (pd.hDC == NULL) {
SetWindowText(ghTextWnd, GetStringRes(IDS_CREPRTDCFAIL));
goto PMF_EXIT;
bSuccess = FALSE;
}

hDCPrinter = pd.hDC;
if (GetEnhMetaFileDescription(hEnhMf, 128, (LPTSTR)buf) == 0) {
strcpy(buf, "No Title");
}

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

SetWindowText(ghTextWnd, GetStringRes(IDS_PRT));

iEntries = GetEnhMetaFilePaletteEntries(hEnhMf, 0, NULL);

if (iEntries) {
if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
sizeof(DWORD) + sizeof(PALETTEENTRY)*iEntries )) == NULL) {
MessageBox(ghwndMain, GetStringRes(IDS_CREPALFAIL),
GetStringRes(IDS_ERROR), MB_OK);
}

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

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

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

GetEnhMetaFileHeader(hEnhMf, sizeof(ENHMETAHEADER), &EnhMetaHdr);


bRCSet = bSetRC2MatchEmfRC(hDCPrinter, EnhMetaHdr, hEnhMf, NULL);
if (!bRCSet) {
vErrOut("bPrintMF: failed");
}

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, GetStringRes(IDS_FMT_PLAYEMFFAIL), 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;
bSuccess = PlayEnhMetaFile(hDCPrinter, hEnhMf, (LPRECT) &rc);
if (!bSuccess) {
char text[128];

wsprintf(text, GetStringRes(IDS_FMT_PLAYEMFFAIL), GetLastError());
OutputDebugString(text);
}
}

// if (gbDB && bSuccess)
// SwapBuffers(hDCPrinter);

EndPage(hDCPrinter);
EndDoc(hDCPrinter);
SetWindowText(ghTextWnd, GetStringRes(IDS_PRTTHRDDONE));

if (bRCSet) {
bCleanUpRC();
}


PMF_EXIT:

ExitThread(0);
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...
*
\**************************************************************************/

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, GetStringRes(IDS_ALLOCPALFAIL),
GetStringRes(IDS_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, GetStringRes(IDS_CREPALFAIL),
GetStringRes(IDS_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.
*
\**************************************************************************/

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, GetStringRes(IDS_HFTONEPALNULL),
GetStringRes(IDS_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, GetStringRes(IDS_PALNULL),
GetStringRes(IDS_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, GetStringRes(IDS_MUSTMSKMCHROMEBM));
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:
*
\**************************************************************************/

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

if ((iNumEntries = GetPaletteEntries(hPalSrc, 0, iNumEntries, NULL)) == 0) {
MessageBox(ghwndMain, GetStringRes(IDS_NOPALENTRYFORCPY),
GetStringRes(IDS_ERROR), MB_OK);
return (HPALETTE) NULL;
}

if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
sizeof(DWORD) + sizeof(PALETTEENTRY)*iNumEntries )) == NULL) {
MessageBox(ghwndMain, GetStringRes(IDS_CPYPALFAIL),
GetStringRes(IDS_ERROR), MB_OK);
return (HPALETTE) NULL;
}

plogPal->palVersion = 0x300;
plogPal->palNumEntries = (WORD) iNumEntries;
pjTmp = (PBYTE) plogPal;
pjTmp += 4;
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:
*
\**************************************************************************/

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
*
\**************************************************************************/

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;

BuildFilterStrs(-1);
BuildFilterStrs(IDS_FT_EPS);
szFilter = BuildFilterStrs(IDS_FT_EMF);

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(), GetStringRes(IDS_MALLOCFAIL),
GetStringRes(IDS_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 MYDBG 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 MYDBG
MessageBox(GetFocus(), GetStringRes(IDS_NULLPTR),
GetStringRes(IDS_ERROR), MB_OK);
#endif
return FALSE;
}

index = 0;

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

if (!bIsAdobe(szKeyWord)) {
MessageBox(GetFocus(), GetStringRes(IDS_NOTADOBE),
GetStringRes(IDS_ERROR), MB_OK);
return FALSE;
}

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

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

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

while ((bGetWord(lpData, szKeyWord, &index)) &&
(!bIsBndBox(szKeyWord))) {
#if MYDBG
MessageBox(GetFocus(), GetStringRes(IDS_SKPTOEOL),
GetStringRes(IDS_ERROR), MB_OK);
#endif
if (!bGoNextLine(lpData, &index)) {
MessageBox(GetFocus(), GetStringRes(IDS_MUSTNOTEOF),
GetStringRes(IDS_ERROR), MB_OK);
return FALSE;
}
}

if (bIsBndBox(szKeyWord)) {
if (bGetWord(lpData, szValue, &index))
prctl->left = atol(szValue);
else {
MessageBox(GetFocus(), GetStringRes(IDS_GETBNDLFTFAIL),
GetStringRes(IDS_ERROR), MB_OK);
return FALSE;
}

if (bGetWord(lpData, szValue, &index))
prctl->top = atol(szValue);
else {
MessageBox(GetFocus(), GetStringRes(IDS_GETBNDTOPFAIL),
GetStringRes(IDS_ERROR), MB_OK);
return FALSE;
}

if (bGetWord(lpData, szValue, &index))
prctl->right = atol(szValue);
else {
MessageBox(GetFocus(), GetStringRes(IDS_GETBNDRGTFAIL),
GetStringRes(IDS_ERROR), MB_OK);
return FALSE;
}

if (bGetWord(lpData, szValue, &index))
prctl->bottom = atol(szValue);
else {
MessageBox(GetFocus(), GetStringRes(IDS_GETBNDBOTFAIL),
GetStringRes(IDS_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 MYDBG
{
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;
}


/***************************************************************************\
* bSetAdvancedGraphics
*
* Set the HDC to advanced graphics mode to get world transforms, and other
* features... However, only do this if we are running on Windows NT, as
* the other platforms don't support GM_ADVANCED.
*
\***************************************************************************/
BOOL bSetAdvancedGraphics(HDC hdc)
{
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);

GetVersionEx (&osvi);
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)

if ((SetGraphicsMode(hdc, GM_ADVANCED)) == 0) {
MessageBox(ghwndMain, GetStringRes(IDS_SETADVGRPHMDFAIL), NULL, MB_OK);
}
return TRUE;
}

/******************************************************************************\
*
* FUNCTION: GetStringRes (int id INPUT ONLY)
*
* COMMENTS: Load the resource string with the ID given, and return a
* pointer to it. Notice that the buffer is common memory so
* the string must be used before this call is made a second time.
*
\******************************************************************************/

LPTSTR GetStringRes (int id)
{
static TCHAR buffer[MAX_PATH];

buffer[0]=0;
LoadString (GetModuleHandle (NULL), id, buffer, MAX_PATH);
return buffer;
}


LPTSTR GetStringRes2 (int id)
{
static TCHAR buffer[MAX_PATH];

buffer[0]=0;
LoadString (GetModuleHandle (NULL), id, buffer, MAX_PATH);
return buffer;
}

/******************************************************************************\
*
* FUNCTION: BuildFilterStrs (int id INPUT ONLY)
*
* COMMENTS: Construct a filter string by a series of LoadString calls. The
*resulting string is as follows: "%OldStr%\0%IDStr%\0%(ID+1)Str%\0\0".
*Note that each consecutive function call appends the new filter
*string on to the end of a static buffer. Call the function with
*id = -1 to reinitialize the buffer.
*
\******************************************************************************/

LPTSTRBuildFilterStrs(int id)
{
static TCHAR buffer[1024];
static TCHAR *pBuf;

if (id == -1)
{
pBuf = buffer;
}
else
{
LoadString(GetModuleHandle (NULL), id, pBuf, 1024 - (pBuf-buffer));
pBuf += strlen(pBuf) + 1;
LoadString(GetModuleHandle (NULL), id + 1, pBuf, 1024 - (pBuf-buffer));
pBuf += strlen(pBuf) + 1;
}

*pBuf = 0;
*(pBuf+1) = 0;
return buffer;
}