/****************************************************************************
16 July 1993 Release Notes

This is a very rudimentary test application to make sure the plumbing
in GDI and ICMs is working. The code is not perfect. Some of the code
is gathered from various SDK applets. Some of the code is redundant.
Some of the code is redundant. A lot of stuff is hard coded for quick
turn around. In short, please do not criticize the code, it is not
meant to be other than it is, quick code to test. There are one or two
intentional bugs for robust GDI testing.


This program was developed using the Win 3.1 SDK, and builds and run
using the chicago tools.

****************************************************************************/



/****************************************************************************

	PROGRAM: icmtest.c

	PURPOSE: Device Independent Color Support

	FUNCTIONS:

		WinMain() - calls initialization function, processes message loop
		InitApplication() - initializes window data and registers window
		InitInstance() - saves instance handle and creates main window
		MainWndProc() - processes messages
		About() - processes messages for "About" dialog box

	COMMENTS:

		Windows can have several copies of your application running at the
		same time. The variable hInst keeps track of which instance this
		application is so that processing will be to the correct window.

****************************************************************************/

#define WINVER 0x0300
#define NOMINMAX
#define NOLOGERROR
#define NOPROFILER
#define NOHELP
#define NORESOURCE
#define NOATOM
#define NOLANGUAGE
#define NODBCS
#define NOKEYBOARDINFO
#define NOGDICAPMASKS
#define NODRAWTEXT
#define NOTEXTMETRIC
#define NOSOUND
#define NOCOMM
#define NODRIVERS
#define NOVIRTUALKEYCODES
#define NOKEYSTATES
#define NOWH
#define NOCLIPBOARD

#include "windows.h"	    /* required for all Windows applications */
#include "icmtest.h"	    /* specific to this program */
#include "showdib.h"	    /* specific to this program */

int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int);
BOOL InitApplication(HANDLE);
BOOL InitInstance(HANDLE, int);
long FAR PASCAL MainWndProc(HWND, unsigned, WORD, LONG);
BOOL FAR PASCAL About(HWND, unsigned, WORD, LONG);
void DIBPaint (HDC,int,int);

int FAR PASCAL EnumCallback(LPSTR lpszMethodName, DWORD ulIdent, LONG lParam);
VOID SelectAndPaintALot(HDC hdc, int xoffset);
VOID SelectPalColorsAndPaintALot(HDC hdc, int xoffset);
VOID PaintALot(HDC hdc, int xoffset);
VOID PaintALotwithPalColors(HDC hdc, int xoffset);


LOGCOLORSPACE GLCS_CS = {0};

LOGCOLORSPACE Gamma18 =

{ 0x400,
  sizeof (LOGCOLORSPACE),
  1,
  1,
  {
    {0x01A5E,0x016E9,0x00B96},
    {0x00DA2,0x02DD3,0x0049C},
    {0x00137,0x0079E,0x03CFE}
  },
  0x1CCCD,
  0x1CCCD,
  0x1CCCD,
  0
};

LOGCOLORSPACE Gamma22 =

{ 0x400,
  sizeof (LOGCOLORSPACE),
  1,
  1,
  {
    {0x01A5E,0x016E9,0x00B96},
    {0x00DA2,0x02DD3,0x0049C},
    {0x00137,0x0079E,0x03CFE}
  },
  0x23333,
  0x23333,
  0x23333,
  "flipper.dcc"
};

LOGCOLORSPACE GammaGBR =

{ 0x400,
  sizeof (LOGCOLORSPACE),
  1,
  1,
  {
    {0x016E9,0x00B96,0x01A5E},
    {0x02DD3,0x0049C,0x00DA2},
    {0x0079E,0x03CFE,0x00137}
  },
  0x10000,
  0x10000,
  0x10000,
  0
};

LOGCOLORSPACE Gamma18RBG =

{ 0x400,
  sizeof (LOGCOLORSPACE),
  1,
  1,
  {
    {0x0102C,0x011EC,0x006C5},
    {0x00950,0x026AD,0x004BE},
    {0x001FF,0x00788,0x03ABF}
  },
  0x1CCCD,
  0x1CCCD,
  0x1CCCD,
  0
};

HCOLORSPACE hGCS_CS = 0;
HCOLORSPACE hdefaultCS = 0;
HCOLORSPACE hCS18 = 0;
HCOLORSPACE hCS22 = 0;
HCOLORSPACE hCSGBR = 0;
HCOLORSPACE hCS18RBG = 0;
HCOLORSPACE hcurColorSpace = 0;

HANDLE  hInst;      /* current instance */
HANDLE  myFileHandle = 0;
HANDLE  myMungeFileHandle = 0;
HANDLE  myhMem       = 0;
LPDWORD mypMem       = 0;
HANDLE	ICBM2	     = 0;
HANDLE	ICBM3	     = 0;
HANDLE	ICBM4	     = 0;
WORD	ICBM2count   = 0;
WORD	ICBM3count   = 0;
WORD	ICBM4count   = 0;
DWORD	ICM_DIC2_ID  = 0;
DWORD	GamutMethod  = 1;
DWORD	cGamutMethod = 1;
HDC	hdcCompat    = 0;

char		GammaBuffer[768] = {0};
char		achDeviceColorFile[130];
char		ach8BitFileName[128]  = "256color.bmp";
char		ach24BitFileName[128] = "24bcolor.bmp";
NPLOGPALETTE	pLogPal;
RECT		rcClip;
static		HCURSOR hcurSave;

BOOL	 fCheckGamut	= FALSE;	/* TRUE if gamut range check is done  */
BOOL	 fMatchTarget	= FALSE;	/* TRUE if matching to target wanted  */
BOOL	 fPalRelRGBs	= FALSE;
BOOL	 f8BitDIB	= TRUE; 	/* TRUE if 8 bit DIB being used       */
BOOL	 fDoDIC 	= FALSE;
HPALETTE hpalCurrent	= NULL; 	/* Handle to current palette	      */
HANDLE	 hdib8Bit	= NULL; 	/* Handle to 8 bit memory DIB	      */
HBITMAP  hbm8Bit	= NULL; 	/* Handle to 8 bit memory BITMAP      */
HANDLE	 hbi8Bit	= NULL; 	/* Handle to 8 bit bitmapinfo struct  */
HANDLE	 hdib24Bit	= NULL; 	/* Handle to 24 bit memory DIB	      */
HBITMAP  hbm24Bit	= NULL; 	/* Handle to 24 bit memory BITMAP     */
HANDLE	 hbi24Bit	= NULL; 	/* Handle to 24 bit bitmapinfo struct */
HANDLE	 hTempBits	= NULL; 	/* buffer for gamut range checking    */

/****************************************************************************

	FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)

	PURPOSE: calls initialization function, processes message loop

	COMMENTS:

		Windows recognizes this function by name as the initial entry point
		for the program.  This function calls the application initialization
		routine, if no other instance of the program is running, and always
		calls the instance initialization routine.  It then executes a message
		retrieval and dispatch loop that is the top-level control structure
		for the remainder of execution.  The loop is terminated when a WM_QUIT
		message is received, at which time this function exits the application
		instance by returning the value passed by PostQuitMessage().

		If this function must abort before entering the message loop, it
		returns the conventional value NULL.

****************************************************************************/

int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	MSG msg;    /* message */

	if (!hPrevInstance)     /* Other instances of app running? */
		if (!InitApplication(hInstance))    /* Initialize shared things */
			return (FALSE);     /* Exits if unable to initialize */

	/* Perform initializations that apply to a specific instance */
	if (!InitInstance(hInstance, nCmdShow))
		return (FALSE);

	/* Acquire and dispatch messages until a WM_QUIT message is received. */
	while (GetMessage(&msg,     /* message structure */
		NULL,   /* handle of window receiving the message */
		NULL,   /* lowest message to examine    */
		NULL))  /* highest message to examine   */
	{
		TranslateMessage(&msg);     /* Translates virtual key codes       */
		DispatchMessage(&msg);      /* Dispatches message to window       */
	}
	return (msg.wParam);        /* Returns the value from PostQuitMessage */
}


/****************************************************************************

	FUNCTION: InitApplication(HANDLE)

	PURPOSE: Initializes window data and registers window class

	COMMENTS:

		This function is called at initialization time only if no other
		instances of the application are running.  This function performs
		initialization tasks that can be done once for any number of running
		instances.

		In this case, we initialize a window class by filling out a data
		structure of type WNDCLASS and calling the Windows RegisterClass()
		function. Since all instances of this application use the same window
		class, we only need to do this when the first instance is initialized.


****************************************************************************/

BOOL InitApplication(HANDLE hInstance)
{
	WNDCLASS  wc;

	/* Fill in window class structure with parameters that describe the
		main window. */

	wc.style = NULL;                /* Class style(s) */
	wc.lpfnWndProc = MainWndProc;   /* Function to retrieve messages for  */
									/* windows of this class */
	wc.cbClsExtra = 0;              /* No per-class extra data */
	wc.cbWndExtra = 0;              /* No per-window extra data */
	wc.hInstance = hInstance;       /* Application that owns the class */
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName =  "ICMTest";	/* Name of menu resource in .RC file. */
	wc.lpszClassName = "GenericWClass"; /* Name used in call to CreateWindow. */

	/* Register the window class and return success/failure code. */
	return (RegisterClass(&wc));
}

/****************************************************************************

	FUNCTION:  InitInstance(HANDLE, int)

	PURPOSE:  Saves instance handle and creates main window

	COMMENTS:

		This function is called at initialization time for every instance of
		this application.  This function performs initialization tasks that
		cannot be shared by multiple instances.

		In this case, we save the instance handle in a static variable and
		create and display the main program window.

****************************************************************************/

BOOL InitInstance(HANDLE hInstance, int nCmdShow)
{
	HWND    hWnd;   /* Main window handle */

	/* Save the instance handle in static variable, which will be used in
	   many subsequence calls from this application to Windows. */

	hInst = hInstance;

	/* Create a main window for this application instance.  */

	hWnd = CreateWindow(
		"GenericWClass",    /* See RegisterClass() call */
		"Device Independent Color Test App",   /* Text for window title bar */
		WS_OVERLAPPEDWINDOW,    /* Window style */
		CW_USEDEFAULT,  /* Default horizontal position */
		CW_USEDEFAULT,  /* Default vertical position */
		CW_USEDEFAULT,  /* Default width */
		CW_USEDEFAULT,  /* Default height */
		NULL,   /* Overlapped windows have no parent */
		NULL,   /* Use the window class menu */
		hInstance,  /* This instance owns this window */
		NULL    /* Pointer not needed */
	);

	/* If window could not be created, return "failure" */

	if (!hWnd)
		return (FALSE);

	/* Make the window visible; update its client area; and return "success" */

	ShowWindow(hWnd, nCmdShow);     /* Show the window */
	UpdateWindow(hWnd);     /* Sends WM_PAINT message */
	return (TRUE);  /* Returns the value from PostQuitMessage */
}

/****************************************************************************

	FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG)

	PURPOSE:  Processes messages

	MESSAGES:

		WM_COMMAND    - application menu (About dialog box)
		WM_DESTROY    - destroy window

	COMMENTS:

		To process the IDM_ABOUT message, call MakeProcInstance() to get the
		current instance address of the About() function.  Then call Dialog
		box which will create the box according to the information in your
		icmtest.rc file and turn control over to the About() function.	When
		it returns, free the intance address.

****************************************************************************/

LONG FAR PASCAL MainWndProc(HWND hWnd, unsigned message, WORD wParam, LONG lParam)
{
    PAINTSTRUCT ps;
    HDC 	hDC;
    OFSTRUCT	FileStruct;
    int 	cRecords;
    char	szBuffer[80];
    int 	xoffset=165;
    WORD	i;
    HPALETTE	hOldPal;

	switch (message)
	{

	    case WM_DESTROY:	      /* message: window being destroyed */
		if (myhMem) GlobalFree(myhMem);
		FreeDibs();
		PostQuitMessage(0);
		break;

	    case WM_CREATE:
		/* Allocate space for our logical palette */
                pLogPal = (NPLOGPALETTE) LocalAlloc( LMEM_FIXED,
                                                     (sizeof(LOGPALETTE) +
                                                     (sizeof(PALETTEENTRY)*(MAXPALETTE))));

                /* If DIB initialization fails, quit */
		if (!InitDIBs(hWnd))
		   PostQuitMessage (3) ;

                break;

	    case WM_ACTIVATE:
                if (!wParam)  /* app. is being de-activated */
                   break;
                /* If the app. is moving to the foreground, fall through and
                 * redraw full client area with the newly realized palette,
                 * if the palette has changed.
                 */

	    case WM_QUERYNEWPALETTE:
                /* If palette realization causes a palette change,
                 * we need to do a full redraw.
                 */
		hDC = GetDC (hWnd);
		if (fDoDIC)
		{
		    EnableICM(hDC,TRUE);
		    if (hcurColorSpace) SetColorSpace(hDC, hcurColorSpace);
		}
		hOldPal = SelectPalette (hDC, hpalCurrent, 0);

		i = RealizePalette(hDC);

		if (fDoDIC) EnableICM(hDC,FALSE);
		SelectPalette (hDC, hOldPal, 0);
		ReleaseDC (hWnd, hDC);

		if (i) {
		    InvalidateRect (hWnd, (LPRECT) (NULL), 1);
		    return 1;
		} else
		    return FALSE;
                break;

	    case WM_PAINT:
		BeginPaint(hWnd, &ps);
		if (!hdefaultCS)
		hcurColorSpace = hdefaultCS = GetColorSpace(ps.hdc);
		hdcCompat = CreateCompatibleDC(ps.hdc);
		fDoDIC = FALSE;

		/* First label the rows. */

		if (!fPalRelRGBs)
		{
		    wsprintf(szBuffer,"Text color:  00808080");
		    TextOut(ps.hdc, 0,	50, szBuffer, lstrlen(szBuffer));
		    wsprintf(szBuffer,"BkColor:     00FF0000");
		    TextOut(ps.hdc, 0,	85, szBuffer, lstrlen(szBuffer));
		    wsprintf(szBuffer,"Pixels:      0000FF00");
		    TextOut(ps.hdc, 0, 120, szBuffer, lstrlen(szBuffer));
		    wsprintf(szBuffer,"Pen color:   00FF00FF");
		    TextOut(ps.hdc, 0, 155, szBuffer, lstrlen(szBuffer));
		    wsprintf(szBuffer,"Brush color: 000000FF");
		    TextOut(ps.hdc, 0, 205, szBuffer, lstrlen(szBuffer));
		}
		else
		{
		    wsprintf(szBuffer,"Text color:  0200BA00");
		    TextOut(ps.hdc, 0,	50, szBuffer, lstrlen(szBuffer));
		    wsprintf(szBuffer,"BkColor:     02710000");
		    TextOut(ps.hdc, 0,	85, szBuffer, lstrlen(szBuffer));
		    wsprintf(szBuffer,"Pixels:      02E61448");
		    TextOut(ps.hdc, 0, 120, szBuffer, lstrlen(szBuffer));
		    wsprintf(szBuffer,"Pen color:   020810BE");
		    TextOut(ps.hdc, 0, 155, szBuffer, lstrlen(szBuffer));
		    wsprintf(szBuffer,"Brush color: 0261796D");
		    TextOut(ps.hdc, 0, 205, szBuffer, lstrlen(szBuffer));
		}
		    wsprintf(szBuffer,"BitBlt");
		    TextOut(ps.hdc, 0, 260, szBuffer, lstrlen(szBuffer));
		    wsprintf(szBuffer,"CreateandBitBlt");
		    TextOut(ps.hdc, 0, 315, szBuffer, lstrlen(szBuffer));
		    wsprintf(szBuffer,"SetDIBitsToDevice");
		    TextOut(ps.hdc, 0, 370, szBuffer, lstrlen(szBuffer));
		    wsprintf(szBuffer,"StretchDIBits");
		    TextOut(ps.hdc, 0, 425, szBuffer, lstrlen(szBuffer));

		/* Do no DIC. This is to see the normal state of affairs. */

		wsprintf(szBuffer,"** No DIC **");
		TextOut(ps.hdc, xoffset,  20, szBuffer, lstrlen(szBuffer));
		if (!fPalRelRGBs)
		    SelectAndPaintALot(ps.hdc, xoffset);
		else
		    SelectPalColorsAndPaintALot(ps.hdc, xoffset);
		xoffset = xoffset + 140;

		/* Enable DIC. All colors should be adjusted. There is a
		   bug currently in GDI where pens and brushes are not
		   getting properly re-realized. */

		wsprintf(szBuffer,"* Enable DIC *");
		TextOut(ps.hdc, xoffset,  20, szBuffer, lstrlen(szBuffer));
		EnableICM(ps.hdc, TRUE);
		SetColorSpace(ps.hdc, hcurColorSpace);
		fDoDIC = TRUE;
		GamutMethod = 1;
		if (!fPalRelRGBs)
		    PaintALot(ps.hdc, xoffset);
		else
		    PaintALotwithPalColors(ps.hdc, xoffset);
		xoffset = xoffset + 140;

		/* Select Objects. All colors should be matching. The
		   selecting forces the realization of pens and brushes. */

		wsprintf(szBuffer,"* Create again *");
		TextOut(ps.hdc, xoffset,  20, szBuffer, lstrlen(szBuffer));
		if (!fPalRelRGBs)
		    SelectAndPaintALot(ps.hdc, xoffset);
		else
		    SelectPalColorsAndPaintALot(ps.hdc, xoffset);
		xoffset = xoffset + 140;

		/* SetGamutMatcher. Uses other than the default matcher. */

		wsprintf(szBuffer,"** SetGMM **");
		TextOut(ps.hdc, xoffset,  20, szBuffer, lstrlen(szBuffer));
		GamutMethod = cGamutMethod;
		SetGamutMatchingMethod(ps.hdc,GamutMethod);

		if (fMatchTarget)
		ColorMatchToTarget(ps.hdc,ps.hdc,CS_ENABLE);

		if (!fPalRelRGBs)
		    SelectAndPaintALot(ps.hdc, xoffset);
		else
		    SelectPalColorsAndPaintALot(ps.hdc, xoffset);
		xoffset = xoffset + 140;

		if (fMatchTarget)
		ColorMatchToTarget(ps.hdc,ps.hdc,CS_DISABLE);

		EndPaint(hWnd,&ps);
		break;

	    case WM_COMMAND:	/* message: command from application menu */
                /* Process menu commands */
                return MenuCommand (hWnd, wParam);
                break;


	    case WM_INITMENU:
		/* check/uncheck menu items depending on state	of related
		 * flags
		 */
		CheckMenuItem(wParam, IDM_CHECKCOLORS,
		    (fCheckGamut ? MF_CHECKED : MF_UNCHECKED));

		CheckMenuItem(wParam, IDM_MATCHTOTARGET,
		    (fMatchTarget ? MF_CHECKED : MF_UNCHECKED));

		CheckMenuItem(wParam, IDM_CRE_GAMMA_18,
		    (hCS18  ? MF_CHECKED : MF_UNCHECKED));
		CheckMenuItem(wParam, IDM_CRE_GAMMA_22,
		    (hCS22  ? MF_CHECKED : MF_UNCHECKED));
		CheckMenuItem(wParam, IDM_CRE_GBR,
		    (hCSGBR  ? MF_CHECKED : MF_UNCHECKED));
		CheckMenuItem(wParam, IDM_CRE_GAMMA_18_RBG,
		    (hCS18RBG  ? MF_CHECKED : MF_UNCHECKED));

		EnableMenuItem(wParam, IDM_SET_GAMMA_18,
		    hCS18 ? MF_ENABLED : MF_GRAYED);
		EnableMenuItem(wParam, IDM_SET_GAMMA_22,
		    hCS22 ? MF_ENABLED : MF_GRAYED);
		EnableMenuItem(wParam, IDM_SET_GBR,
		    hCSGBR ? MF_ENABLED : MF_GRAYED);
		EnableMenuItem(wParam, IDM_SET_GAMMA_18_RBG,
		    hCS18RBG ? MF_ENABLED : MF_GRAYED);
		CheckMenuItem(wParam, IDM_SET_DEFAULT_CS,
		    hcurColorSpace == hdefaultCS ? MF_CHECKED : MF_UNCHECKED);
		CheckMenuItem(wParam, IDM_SET_GAMMA_18,
		    hcurColorSpace == hCS18	 ? MF_CHECKED : MF_UNCHECKED);
		CheckMenuItem(wParam, IDM_SET_GAMMA_22,
		    hcurColorSpace == hCS22	 ? MF_CHECKED : MF_UNCHECKED);
		CheckMenuItem(wParam, IDM_SET_GBR,
		    hcurColorSpace == hCSGBR	 ? MF_CHECKED : MF_UNCHECKED);
		CheckMenuItem(wParam, IDM_SET_GAMMA_18_RBG,
		    hcurColorSpace == hCS18RBG	 ? MF_CHECKED : MF_UNCHECKED);

		EnableMenuItem(wParam, IDM_DEL_GAMMA_18,
		    hCS18 ? MF_ENABLED : MF_GRAYED);
		EnableMenuItem(wParam, IDM_DEL_GAMMA_22,
		    hCS22 ? MF_ENABLED : MF_GRAYED);
		EnableMenuItem(wParam, IDM_DEL_GBR,
		    hCSGBR ? MF_ENABLED : MF_GRAYED);
		EnableMenuItem(wParam, IDM_DEL_GAMMA_18_RBG,
		    hCS18RBG ? MF_ENABLED : MF_GRAYED);

		CheckMenuItem(wParam, IDM_SGMM_LUM_D,
		    (cGamutMethod == 1 ? MF_CHECKED : MF_UNCHECKED));
		CheckMenuItem(wParam, IDM_SGMM_HUE_D,
		    (cGamutMethod == 2	? MF_CHECKED : MF_UNCHECKED));
		CheckMenuItem(wParam, IDM_SGMM_SAT_D,
		    (cGamutMethod == 3	? MF_CHECKED : MF_UNCHECKED));
		CheckMenuItem(wParam, IDM_SGMM_LUM_2,
		    ICM_DIC2_ID && (cGamutMethod == (ICM_DIC2_ID | 1)) ? MF_CHECKED : MF_UNCHECKED);
		CheckMenuItem(wParam, IDM_SGMM_HUE_2,
		    ICM_DIC2_ID && (cGamutMethod == (ICM_DIC2_ID | 2)) ? MF_CHECKED : MF_UNCHECKED);
		CheckMenuItem(wParam, IDM_SGMM_SAT_2,
		    ICM_DIC2_ID && (cGamutMethod == (ICM_DIC2_ID | 3)) ? MF_CHECKED : MF_UNCHECKED);

		EnableMenuItem(wParam, IDM_SGMM_LUM_2,
		    ICBM2 && ICM_DIC2_ID ? MF_ENABLED : MF_GRAYED);
		EnableMenuItem(wParam, IDM_SGMM_HUE_2,
		    ICBM2 && ICM_DIC2_ID ? MF_ENABLED : MF_GRAYED);
		EnableMenuItem(wParam, IDM_SGMM_SAT_2,
		    ICBM2 && ICM_DIC2_ID ? MF_ENABLED : MF_GRAYED);

		CheckMenuItem(wParam, IDM_FREE_ICM_2,
		    (ICBM2count ? MF_CHECKED : MF_UNCHECKED));
		CheckMenuItem(wParam, IDM_FREE_ICM_3,
		    (ICBM3count ? MF_CHECKED : MF_UNCHECKED));
		CheckMenuItem(wParam, IDM_FREE_ICM_4,
		    (ICBM4count ? MF_CHECKED : MF_UNCHECKED));

		CheckMenuItem(wParam, IDM_RGBS,
		    (!(fPalRelRGBs) ? MF_CHECKED : MF_UNCHECKED));
		CheckMenuItem(wParam, IDM_PALETTERGBS,
		    (  fPalRelRGBs  ? MF_CHECKED : MF_UNCHECKED));

		CheckMenuItem(wParam, IDM_8BITDIB,
		    ( (f8BitDIB) ? MF_CHECKED : MF_UNCHECKED));
		CheckMenuItem(wParam, IDM_24BITDIB,
		    (!(f8BitDIB) ? MF_CHECKED : MF_UNCHECKED));

		break;

	    default:		/* Passes it on if unproccessed    */
		return (DefWindowProc(hWnd, message, wParam, lParam));
	}
	return (NULL);
}


/****************************************************************************
 *                                                                          *
 *  FUNCTION   : MenuCommand ( HWND hWnd, WORD wParam)                      *
 *                                                                          *
 *  PURPOSE    : Processes menu commands.                                   *
 *                                                                          *
 *  RETURNS    : TRUE  - if command could be processed.                     *
 *               FALSE - otherwise                                          *
 *                                                                          *
 ****************************************************************************/
BOOL MenuCommand (hWnd, id)
HWND hWnd;
WORD id;

{
    char		Name[40];
    BITMAPINFOHEADER	bi;
    HDC 		hDC;
    int 		xSize, ySize, xRes, yRes, dx, dy;
    RECT		Rect;
    PAINTSTRUCT 	ps;
    FARPROC		lpProcAbout;	/* pointer to the "About" function */
    LOGCOLORSPACE	lcs;


    switch (id) {

	case IDM_OPEN:
	case IDM_SAVE:
		break;

        case IDM_PRINT:
                GetWindowText(hWnd, Name, sizeof(Name));

		if (f8BitDIB)
		{
		DibInfo(hbi8Bit, &bi);
		}
		else
		{
		DibInfo(hbi24Bit, &bi);
		}


                if (!IsRectEmpty(&rcClip))
                {
                    bi.biWidth  = rcClip.right  - rcClip.left;
                    bi.biHeight = rcClip.bottom - rcClip.top;
                }

                /* Initialise printer stuff */
                if (!(hDC = GetPrinterDC()))
                        break;

		if (hDC)
		{
		    EnableICM(hDC,TRUE);
		    if (hcurColorSpace) SetColorSpace(hDC, hcurColorSpace);
		}

                xSize = GetDeviceCaps(hDC, HORZRES);
                ySize = GetDeviceCaps(hDC, VERTRES);
                xRes  = GetDeviceCaps(hDC, LOGPIXELSX);
                yRes  = GetDeviceCaps(hDC, LOGPIXELSY);

                /* Use half inch margins on left and right
                 * and one inch on top. Maintain the same aspect ratio.
                 */

                dx = xSize - xRes;
                dy = (int)((long)dx * bi.biHeight/bi.biWidth);

                /* Fix bounding rectangle for the picture .. */
                Rect.top    = yRes;
                Rect.left   = xRes / 2;
                Rect.bottom = yRes + dy;
                Rect.right  = xRes / 2 + dx;

                /* ... and inform the driver */
                Escape(hDC, SET_BOUNDS, sizeof(RECT), (LPSTR)&Rect, NULL);

                if (InitPrinting(hDC, hWnd, hInst, Name)) {

                        PrintDIB(hWnd, hDC, xRes/2, yRes, dx, dy);

                        /* Signal to the driver to begin translating the drawing
                         * commands to printer output...
                         */
                        Escape (hDC, NEWFRAME, NULL, NULL, NULL);

                        TermPrinting(hDC);
                }

                DeleteDC(hDC);
                break;


        case IDM_EXIT:
                PostMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
                break;

	case IDM_ENABLEICM:
		break;

	case IDM_GETCOLORSPACE:
		BeginPaint(hWnd, &ps);
		hGCS_CS = GetColorSpace(ps.hdc);
		EndPaint(hWnd,&ps);
		break;

	case IDM_GETLOGCOLORSPACE:
		hGCS_CS = GetColorSpace(ps.hdc);
		GetLogColorSpace(hGCS_CS,&GLCS_CS,sizeof(LOGCOLORSPACE));
		break;

	case IDM_CREATECOLORSPACE:
	case IDM_CRE_GAMMA_18:
		if (!hCS18)
		hCS18 = CreateColorSpace(&Gamma18);
		break;

	case IDM_CRE_GAMMA_22:
		if (!hCS22)
		hCS22 = CreateColorSpace(&Gamma22);
		break;

	case IDM_CRE_GBR:
		if (!hCSGBR)
		hCSGBR = CreateColorSpace(&GammaGBR);
		break;

	case IDM_CRE_GAMMA_18_RBG:
		if (!hCS18RBG)
		hCS18RBG = CreateColorSpace(&Gamma18RBG);
		break;

	case IDM_SETCOLORSPACE:
	case IDM_SET_DEFAULT_CS:
		hcurColorSpace = hdefaultCS;
		break;

	case IDM_SET_GAMMA_18:
		if (hCS18)
		hcurColorSpace = hCS18;
		break;

	case IDM_SET_GAMMA_22:
		if (hCS22)
		hcurColorSpace = hCS22;
		break;

	case IDM_SET_GBR:
		if (hCSGBR)
		hcurColorSpace = hCSGBR;
		break;

	case IDM_SET_GAMMA_18_RBG:
		if (hCS18RBG)
		hcurColorSpace = hCS18RBG;
		break;

	case IDM_DELETECOLORSPACE:
	case IDM_DEL_GAMMA_18:
		if ((hCS18) && !(hcurColorSpace == hCS18))
		{
		    DeleteColorSpace(hCS18);
		    hCS18 = 0;
		}
		break;

	case IDM_DEL_GAMMA_22:
		if ((hCS22) && !(hcurColorSpace == hCS22))
		{
		    DeleteColorSpace(hCS22);
		    hCS22 = 0;
		}
		break;

	case IDM_DEL_GBR:
		if ((hCSGBR) && !(hcurColorSpace == hCSGBR))
		{
		    DeleteColorSpace(hCSGBR);
		    hCSGBR = 0;
		}
		break;

	case IDM_DEL_GAMMA_18_RBG:
		if ((hCS18RBG) && !(hcurColorSpace == hCS18RBG))
		{
		    DeleteColorSpace(hCS18RBG);
		    hCS18RBG = 0;
		}
		break;

	case IDM_CHECKCOLORS:
		fCheckGamut = !fCheckGamut;
		break;

	case IDM_MATCHTOTARGET:
		fMatchTarget = !fMatchTarget;
		break;

	case IDM_ENUMERATEGMM:
		BeginPaint(hWnd, &ps);
		lpProcAbout = MakeProcInstance(EnumCallback, hInst);
		EnumGamutMatchingMethods(ps.hdc,lpProcAbout,0);
		FreeProcInstance(lpProcAbout);
		EndPaint(hWnd,&ps);
		break;

	case IDM_GETGMM:
		break;

	case IDM_SETGMM:
	case IDM_SGMM_LUM_D:
		cGamutMethod = 1;
		break;

	case IDM_SGMM_HUE_D:
		cGamutMethod = 2;
		break;

	case IDM_SGMM_SAT_D:
		cGamutMethod = 3;
		break;

	case IDM_SGMM_LUM_2:
		cGamutMethod = ICM_DIC2_ID | 1;
		break;

	case IDM_SGMM_HUE_2:
		cGamutMethod = ICM_DIC2_ID | 2;
		break;

	case IDM_SGMM_SAT_2:
		cGamutMethod = ICM_DIC2_ID | 3;
		break;

	case IDM_LOAD_ICM_2:
		ICBM2 = LoadImageColorMatcher("DIC2.DLL");
		ICBM2count++;
		break;

	case IDM_LOAD_ICM_3:
		ICBM3 = LoadImageColorMatcher("DIC3.DLL");
		ICBM3count++;
		break;

	case IDM_LOAD_ICM_4:
		ICBM4 = LoadImageColorMatcher("DIC4.DLL");
		ICBM4count++;
		break;

	case IDM_FREE_ICM_2:
		FreeImageColorMatcher(ICBM2);
		if (ICBM2count)
		{
		    ICBM2count--;
		    ICM_DIC2_ID = 0;
		}
		break;

	case IDM_FREE_ICM_3:
		FreeImageColorMatcher(ICBM3);
		if (ICBM3count) ICBM3count--;
		break;

	case IDM_FREE_ICM_4:
		FreeImageColorMatcher(ICBM4);
		if (ICBM4count) ICBM4count--;
		break;

	case IDM_GETCOLORPROFILE:
		BeginPaint(hWnd, &ps);
		GetColorProfile(ps.hdc,achDeviceColorFile,130);
		EndPaint(hWnd,&ps);
		break;

	case IDM_SETCOLORPROFILE:
		BeginPaint(hWnd, &ps);
		SetColorProfile(ps.hdc,achDeviceColorFile);
		EndPaint(hWnd,&ps);
		break;

	case IDM_GETGAMMARAMP:
		BeginPaint(hWnd, &ps);
		GetDeviceGammaRamp(ps.hdc,&GammaBuffer);
		EndPaint(hWnd,&ps);
		break;

	case IDM_SETGAMMARAMP:
		BeginPaint(hWnd, &ps);
		SetDeviceGammaRamp(ps.hdc,&GammaBuffer);
		EndPaint(hWnd,&ps);
		break;

	case IDM_TEST:
		InvalidateRect(hWnd,NULL,TRUE);
		break;

	case IDM_RGBS:
		fPalRelRGBs = FALSE;
		break;

	case IDM_PALETTERGBS:
		fPalRelRGBs = TRUE;
		break;

	case IDM_8BITDIB:
		f8BitDIB = TRUE;
		break;

	case IDM_24BITDIB:
		f8BitDIB = FALSE;
		break;

        case IDM_ABOUT:
		lpProcAbout = MakeProcInstance(About, hInst);

		DialogBox(hInst,	/* current instance	    */
			  "AboutBox",	/* resource to use	*/
			  hWnd, 	/* parent handle	*/
			  lpProcAbout); /* About() instance address */

		FreeProcInstance(lpProcAbout);
		break;

        default:
                break;
    }

    return TRUE;
}

/****************************************************************************

	FUNCTION: About(HWND, unsigned, WORD, LONG)

	PURPOSE:  Processes messages for "About" dialog box

	MESSAGES:

		WM_INITDIALOG - initialize dialog box
		WM_COMMAND    - Input received

	COMMENTS:

		No initialization is needed for this particular dialog box, but TRUE
		must be returned to Windows.

		Wait for user to click on "Ok" button, then close the dialog box.

****************************************************************************/

BOOL FAR PASCAL About(HWND hDlg, unsigned message, WORD wParam, LONG lParam)
{
	switch (message)
	{
		case WM_INITDIALOG:     /* message: initialize dialog box */
			return (TRUE);

		case WM_COMMAND:    /* message: received a command */
			if (wParam == IDOK || wParam == IDCANCEL)
			{
				EndDialog(hDlg, TRUE);  /* Exits the dialog box */
				return (TRUE);
			}
			break;
	}
	return (FALSE);     /* Didn't process a message */
}

/****************************************************************************/

int FAR PASCAL EnumCallback(LPSTR lpszMethodName, DWORD ulIdent, LONG lParam)
{
	if ((ulIdent & 0xFF00L) == 0x0200L)
	    ICM_DIC2_ID = ulIdent & 0xFFFFFF00;
	return(1);
}


/****************************************************************************/

VOID SelectAndPaintALot(HDC hdc, int xoffset)

{
	HBRUSH	hBrush;
	HPEN	hPen;
	int	i,j;
	int	yoffset = 50;
	char    szBuffer[80];
	COLORREF tempPixel;

	SetTextColor(hdc, RGB(0x80,0x80,0x80));
	wsprintf(szBuffer,"Text Color");
	TextOut(hdc, xoffset + 15, yoffset, szBuffer, lstrlen(szBuffer));
	yoffset = yoffset + 35;
	SetBkColor(hdc, RGB(0xFF,0x00,0x00));
	wsprintf(szBuffer,"Bkcolor");
	TextOut(hdc, xoffset + 20, yoffset, szBuffer, lstrlen(szBuffer));
	yoffset = yoffset + 35;
	for(i = 0; i < 20; i++)
	{
	    for(j = 0; j < 35; j++)
	    {
		SetPixel(hdc, xoffset + j + 15, yoffset + i, RGB(0x00,0xFF,0x00));
		tempPixel = GetPixel(hdc, xoffset + j + 15, yoffset + i);
		SetPixel(hdc, xoffset + j + 51, yoffset + i, tempPixel);
	    }
	}
	yoffset = yoffset + 35;

	hPen = CreatePen(PS_SOLID, 1, RGB(0xFF,0x00,0xFF));
	SelectObject(hdc, hPen);
	for(i = 0; i < 20; i++)
	{
	    MoveTo(hdc, xoffset,       yoffset + i);
	    LineTo(hdc, xoffset + 100, yoffset + i);
	}
	yoffset = yoffset + 35;

	hBrush = CreateSolidBrush(RGB(0x00,0x00,0xFF));
	SelectObject(hdc, hBrush);
	Rectangle(hdc, xoffset, yoffset, xoffset + 100, yoffset + 50);
	yoffset = yoffset + 60;

	DIBPaint(hdc, xoffset + 8, yoffset);
}

/****************************************************************************/

VOID SelectPalColorsAndPaintALot(HDC hdc, int xoffset)

{
	HBRUSH	hBrush;
	HPEN	hPen;
	int	i,j;
	int	yoffset = 50;
	char	szBuffer[80];
	COLORREF tempPixel;

	SetTextColor(hdc, PALETTERGB(0,186,0));
	wsprintf(szBuffer,"Text Color");
	TextOut(hdc, xoffset + 15, yoffset, szBuffer, lstrlen(szBuffer));
	yoffset = yoffset + 35;
	SetBkColor(hdc, PALETTERGB(113,0,0));
	wsprintf(szBuffer,"Bkcolor");
	TextOut(hdc, xoffset + 20, yoffset, szBuffer, lstrlen(szBuffer));
	yoffset = yoffset + 35;
	for(i = 0; i < 20; i++)
	{
	    for(j = 0; j < 35; j++)
	    {
		SetPixel(hdc, xoffset + j + 15, yoffset + i, PALETTERGB(230,20,72));
		tempPixel = GetPixel(hdc, xoffset + j + 15, yoffset + i);
		SetPixel(hdc, xoffset + j + 51, yoffset + i, tempPixel);
	    }
	}
	yoffset = yoffset + 35;

	hPen = CreatePen(PS_SOLID, 1, PALETTERGB(8,16,190));
	SelectObject(hdc, hPen);
	for(i = 0; i < 20; i++)
	{
	    MoveTo(hdc, xoffset,       yoffset + i);
	    LineTo(hdc, xoffset + 100, yoffset + i);
	}
	yoffset = yoffset + 35;

	hBrush = CreateSolidBrush(PALETTERGB(97,121,109));
	SelectObject(hdc, hBrush);
	Rectangle(hdc, xoffset, yoffset, xoffset + 100, yoffset + 50);
	yoffset = yoffset + 60;

	DIBPaint(hdc, xoffset + 8, yoffset);
}

/****************************************************************************/

VOID PaintALot(HDC hdc, int xoffset)
{
	int	i,j;
	int	yoffset = 50;
	char	szBuffer[80];
	COLORREF tempPixel;

	wsprintf(szBuffer,"Text Color");
	TextOut(hdc, xoffset + 15, yoffset, szBuffer, lstrlen(szBuffer));
	yoffset = yoffset + 35;
	wsprintf(szBuffer,"Bkcolor");
	TextOut(hdc, xoffset + 20, yoffset, szBuffer, lstrlen(szBuffer));
	yoffset = yoffset + 35;
	for(i = 0; i < 20; i++)
	{
	    for(j = 0; j < 35; j++)
	    {
		SetPixel(hdc, xoffset + j + 15, yoffset + i, RGB(0x00,0xFF,0x00));
		tempPixel = GetPixel(hdc, xoffset + j + 15, yoffset + i);
		SetPixel(hdc, xoffset + j + 51, yoffset + i, tempPixel);
	    }
	}
	yoffset = yoffset + 35;

	for(i = 0; i < 20; i++)
	{
	    MoveTo(hdc, xoffset,       yoffset + i);
	    LineTo(hdc, xoffset + 100, yoffset + i);
	}
	yoffset = yoffset + 35;

	Rectangle(hdc, xoffset, yoffset, xoffset + 100, yoffset + 50);
	yoffset = yoffset + 60;

	DIBPaint(hdc, xoffset + 8, yoffset);
}

/****************************************************************************/

VOID PaintALotwithPalColors(HDC hdc, int xoffset)
{
	int	i,j;
	int	yoffset = 50;
	char    szBuffer[80];
	COLORREF tempPixel;

	wsprintf(szBuffer,"Text Color");
	TextOut(hdc, xoffset + 15, yoffset, szBuffer, lstrlen(szBuffer));
	yoffset = yoffset + 35;
	wsprintf(szBuffer,"Bkcolor");
	TextOut(hdc, xoffset + 20, yoffset, szBuffer, lstrlen(szBuffer));
	yoffset = yoffset + 35;
	for(i = 0; i < 20; i++)
	{
	    for(j = 0; j < 35; j++)
	    {
		SetPixel(hdc, xoffset + j + 15, yoffset + i, PALETTERGB(230,20,72));
		tempPixel = GetPixel(hdc, xoffset + j + 15, yoffset + i);
		SetPixel(hdc, xoffset + j + 51, yoffset + i, tempPixel);
	    }
	}

	yoffset = yoffset + 35;

	for(i = 0; i < 20; i++)
	{
	    MoveTo(hdc, xoffset,       yoffset + i);
	    LineTo(hdc, xoffset + 100, yoffset + i);
	}
	yoffset = yoffset + 35;

	Rectangle(hdc, xoffset, yoffset, xoffset + 100, yoffset + 50);
	yoffset = yoffset + 60;

	DIBPaint(hdc, xoffset + 8, yoffset);
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : InitDIBs(hWnd) 					    *
 *                                                                          *
 *  PURPOSE    : Reads a DIB from a file, obtains a handle to it's          *
 *               BITMAPINFO struct., sets up the palette and loads the DIB. *
 *                                                                          *
 *  RETURNS    : TRUE  - DIB loads ok                                       *
 *               FALSE - otherwise                                          *
 *                                                                          *
 ****************************************************************************/
int InitDIBs(hWnd)
HWND hWnd;
{
    unsigned		fh8,fh24;
    LPBITMAPINFOHEADER	lpbi;
    BYTE FAR *		lpv1;
    BYTE FAR *		lpv2;
    WORD FAR *		pw;
    int 		i;
    DWORD		j;
    BITMAPINFOHEADER	bi8Bit,bi24Bit;
    OFSTRUCT		of;

    FreeDibs();

    /* Open the files and get a handle to it's BITMAPINFO */

    fh8 = OpenFile (ach8BitFileName, (LPOFSTRUCT)&of, OF_READ);
    if (fh8 == -1) {
	ErrMsg("Can't open file '%ls'", (LPSTR)ach8BitFileName);
        return FALSE;
    }

    fh24 = OpenFile (ach24BitFileName, (LPOFSTRUCT)&of, OF_READ);
    if (fh24 == -1) {
	ErrMsg("Can't open file '%ls'", (LPSTR)ach24BitFileName);
	_lclose (fh8);
        return FALSE;
    }


    hbi8Bit = ReadDibBitmapInfo(fh8);
    _lclose (fh8);
    hbi24Bit = ReadDibBitmapInfo(fh24);
    _lclose (fh24);

    if (hbi8Bit == NULL){
	ErrMsg("%ls is not a Legitimate DIB File!", (LPSTR)ach8BitFileName);
        return FALSE;
    }
    if (hbi24Bit == NULL){
	ErrMsg("%ls is not a Legitimate DIB File!", (LPSTR)ach24BitFileName);
        return FALSE;
    }
    DibInfo(hbi8Bit ,&bi8Bit );
    DibInfo(hbi24Bit,&bi24Bit);

    /* Set up the palette */
    hpalCurrent = CreateDibPalette(hbi8Bit);
    if (hpalCurrent == NULL) {
        ErrMsg("CreatePalette() Failed");
        return FALSE;
    }

    /*  Convert the DIB color table to palette relative indexes, so
     *  SetDIBits() and SetDIBitsToDevice() can avoid color matching.
     *  We can do this because the palette we realize is identical
     *  to the color table of the bitmap, ie the indexes match 1 to 1
     *
     *  Now that the DIB color table is palette indexes not RGB values
     *  we must use DIB_PAL_COLORS as the wUsage parameter to SetDIBits()
     */
    lpbi = (VOID FAR *)GlobalLock(hbi8Bit);
    if (lpbi->biBitCount != 24) {

        pw = (WORD FAR *)((LPSTR)lpbi + lpbi->biSize);

        for (i=0; i<(int)lpbi->biClrUsed; i++)
            *pw++ = (WORD)i;
    }
    GlobalUnlock(hbi8Bit);

    /*	Copy the DIBs into memory DIB */
    hdib8Bit  = OpenDIB(ach8BitFileName );
    hdib24Bit = OpenDIB(ach24BitFileName);

    /*	If the DIB is RLE or could not be loaded, exit gracefully NOW */
    if ((bi8Bit.biCompression != BI_RGB) || !hdib8Bit){
        ErrMsg ("Could not load RLE!");
	FreeDibs();
        return FALSE;
    }

    /*	Get DDBs from the DIBs */
    hbm8Bit  = BitmapFromDib(hdib8Bit,hpalCurrent);
    if (!hbm8Bit){
	ErrMsg ("Could not create 8 bit bitmap!");
	FreeDibs();
	return FALSE;
    }
    hbm24Bit  = BitmapFromDib(hdib24Bit,hpalCurrent);
    if (!hbm24Bit){
	ErrMsg ("Could not create 24 bit bitmap!");
	FreeDibs();
	return FALSE;
    }

    /* Get a temp buffer for out of gamut checking */
    hTempBits = GlobalAlloc (GHND, GlobalSize(hdib24Bit));
    lpv1=(BYTE FAR *)GlobalLock(hdib24Bit);
    lpv2=(BYTE FAR *)GlobalLock(hTempBits);
    for (j=0; j < GlobalSize(hdib24Bit); j++)
	*lpv2++ = *lpv1++;
    GlobalUnlock(hdib24Bit);
    GlobalUnlock(hTempBits);
    return TRUE;
}
/****************************************************************************
 *                                                                          *
 *  FUNCTION   : ReadDibBitmapInfo(int fh)                                  *
 *                                                                          *
 *  PURPOSE    : Will read a file in DIB format and return a global HANDLE  *
 *               to it's BITMAPINFO.  This function will work with both     *
 *               "old" (BITMAPCOREHEADER) and "new" (BITMAPINFOHEADER)      *
 *               bitmap formats, but will always return a "new" BITMAPINFO  *
 *                                                                          *
 *  RETURNS    : A handle to the BITMAPINFO of the DIB in the file.         *
 *                                                                          *
 ****************************************************************************/
HANDLE ReadDibBitmapInfo (fh)
int fh;
{
    DWORD     off;
    HANDLE    hbi = NULL;
    int       size;
    int       i;
    WORD      nNumColors;

    RGBQUAD FAR       *pRgb;
    BITMAPINFOHEADER   bi;
    BITMAPCOREHEADER   bc;
    LPBITMAPINFOHEADER lpbi;
    BITMAPFILEHEADER   bf;
    DWORD              dwWidth = 0;
    DWORD              dwHeight = 0;
    WORD               wPlanes, wBitCount;

    if (fh == -1)
        return NULL;

    /* Reset file pointer and read file header */
    off = _llseek(fh, 0L, SEEK_CUR);
    if (sizeof (bf) != _lread (fh, (LPSTR)&bf, sizeof (bf)))
        return FALSE;

    /* Do we have a RC HEADER? */
    if (!ISDIB (bf.bfType)) {
        bf.bfOffBits = 0L;
        _llseek (fh, off, SEEK_SET);
    }
    if (sizeof (bi) != _lread (fh, (LPSTR)&bi, sizeof(bi)))
        return FALSE;

    nNumColors = DibNumColors (&bi);

    /* Check the nature (BITMAPINFO or BITMAPCORE) of the info. block
     * and extract the field information accordingly. If a BITMAPCOREHEADER,
     * transfer it's field information to a BITMAPINFOHEADER-style block
     */
    switch (size = (int)bi.biSize){
        case sizeof (BITMAPINFOHEADER):
            break;

        case sizeof (BITMAPCOREHEADER):

            bc = *(BITMAPCOREHEADER*)&bi;

            dwWidth   = (DWORD)bc.bcWidth;
            dwHeight  = (DWORD)bc.bcHeight;
            wPlanes   = bc.bcPlanes;
            wBitCount = bc.bcBitCount;

            bi.biSize               = sizeof(BITMAPINFOHEADER);
            bi.biWidth              = dwWidth;
            bi.biHeight             = dwHeight;
            bi.biPlanes             = wPlanes;
            bi.biBitCount           = wBitCount;

            bi.biCompression        = BI_RGB;
            bi.biSizeImage          = 0;
            bi.biXPelsPerMeter      = 0;
            bi.biYPelsPerMeter      = 0;
            bi.biClrUsed            = nNumColors;
            bi.biClrImportant       = nNumColors;

            _llseek (fh, (LONG)sizeof (BITMAPCOREHEADER) - sizeof (BITMAPINFOHEADER), SEEK_CUR);
            break;

        default:
            /* Not a DIB! */
            return NULL;
    }

    /*  Fill in some default values if they are zero */
    if (bi.biSizeImage == 0){
        bi.biSizeImage = WIDTHBYTES ((DWORD)bi.biWidth * bi.biBitCount)
                         * bi.biHeight;
    }
    if (bi.biClrUsed == 0)
        bi.biClrUsed = DibNumColors(&bi);

    /* Allocate for the BITMAPINFO structure and the color table. */
    hbi = GlobalAlloc (GHND, (LONG)bi.biSize + nNumColors * sizeof(RGBQUAD));
    if (!hbi)
        return NULL;
    lpbi = (VOID FAR *)GlobalLock (hbi);
    *lpbi = bi;

    /* Get a pointer to the color table */
    pRgb = (RGBQUAD FAR *)((LPSTR)lpbi + bi.biSize);
    if (nNumColors){
        if (size == sizeof(BITMAPCOREHEADER)){
            /* Convert a old color table (3 byte RGBTRIPLEs) to a new
             * color table (4 byte RGBQUADs)
             */
            _lread (fh, (LPSTR)pRgb, nNumColors * sizeof(RGBTRIPLE));

            for (i = nNumColors - 1; i >= 0; i--){
                RGBQUAD rgb;

                rgb.rgbRed      = ((RGBTRIPLE FAR *)pRgb)[i].rgbtRed;
                rgb.rgbBlue     = ((RGBTRIPLE FAR *)pRgb)[i].rgbtBlue;
                rgb.rgbGreen    = ((RGBTRIPLE FAR *)pRgb)[i].rgbtGreen;
                rgb.rgbReserved = (BYTE)0;

                pRgb[i] = rgb;
            }
        }
        else
            _lread(fh,(LPSTR)pRgb,nNumColors * sizeof(RGBQUAD));
    }

    if (bf.bfOffBits != 0L)
        _llseek(fh,off + bf.bfOffBits,SEEK_SET);

    GlobalUnlock(hbi);
    return hbi;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : ErrMsg (PSTR sz,...)                                       *
 *                                                                          *
 *  PURPOSE    : Opens a Message box with a error message in it.The user can*
 *               select the OK button to continue                           *
 *                                                                          *
 *  RETURNS    : FALSE to indicate an error has occured.                    *
 *                                                                          *
 ****************************************************************************/
int ErrMsg (PSTR sz,...)
{
    char ach[128];

    wvsprintf (ach, sz, (LPSTR)(&sz+1));   /* Format the string */
    MessageBox (NULL, ach, NULL, MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL);
    return FALSE;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : CreateBIPalette(LPBITMAPINFOHEADER lpbi)                   *
 *                                                                          *
 *  PURPOSE    : Given a Pointer to a BITMAPINFO struct will create a       *
 *               a GDI palette object from the color table.                 *
 *                                                                          *
 *  RETURNS    : A handle to the palette.                                   *
 *                                                                          *
 ****************************************************************************/
HPALETTE CreateBIPalette (lpbi)
LPBITMAPINFOHEADER lpbi;
{
    LOGPALETTE          *pPal;
    HPALETTE            hpal = NULL;
    WORD                nNumColors;
    BYTE                red;
    BYTE                green;
    BYTE                blue;
    WORD                i;
    RGBQUAD        FAR *pRgb;

    if (!lpbi)
        return NULL;

    if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
        return NULL;

    /* Get a pointer to the color table and the number of colors in it */
    pRgb = (RGBQUAD FAR *)((LPSTR)lpbi + (WORD)lpbi->biSize);
    nNumColors = DibNumColors(lpbi);

    if (nNumColors){
        /* Allocate for the logical palette structure */
        pPal = (LOGPALETTE*)LocalAlloc(LPTR,sizeof(LOGPALETTE) + nNumColors * sizeof(PALETTEENTRY));
        if (!pPal)
            return NULL;

        pPal->palNumEntries = nNumColors;
        pPal->palVersion    = PALVERSION;

        /* Fill in the palette entries from the DIB color table and
         * create a logical color palette.
         */
        for (i = 0; i < nNumColors; i++){
            pPal->palPalEntry[i].peRed   = pRgb[i].rgbRed;
            pPal->palPalEntry[i].peGreen = pRgb[i].rgbGreen;
            pPal->palPalEntry[i].peBlue  = pRgb[i].rgbBlue;
            pPal->palPalEntry[i].peFlags = (BYTE)0;
        }
        hpal = CreatePalette(pPal);
        LocalFree((HANDLE)pPal);
    }
    else if (lpbi->biBitCount == 24){
        /* A 24 bitcount DIB has no color table entries so, set the number of
         * to the maximum value (256).
         */
        nNumColors = MAXPALETTE;
        pPal = (LOGPALETTE*)LocalAlloc(LPTR,sizeof(LOGPALETTE) + nNumColors * sizeof(PALETTEENTRY));
        if (!pPal)
            return NULL;

        pPal->palNumEntries = nNumColors;
        pPal->palVersion    = PALVERSION;

        red = green = blue = 0;

        /* Generate 256 (= 8*8*4) RGB combinations to fill the palette
         * entries.
         */
        for (i = 0; i < pPal->palNumEntries; i++){
            pPal->palPalEntry[i].peRed   = red;
            pPal->palPalEntry[i].peGreen = green;
            pPal->palPalEntry[i].peBlue  = blue;
            pPal->palPalEntry[i].peFlags = (BYTE)0;

            if (!(red += 32))
                if (!(green += 32))
                    blue += 64;
        }
        hpal = CreatePalette(pPal);
        LocalFree((HANDLE)pPal);
    }
    return hpal;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : CreateDibPalette(HANDLE hbi)                               *
 *                                                                          *
 *  PURPOSE    : Given a Global HANDLE to a BITMAPINFO Struct               *
 *               will create a GDI palette object from the color table.     *
 *               (BITMAPINFOHEADER format DIBs only)                                     *
 *                                                                          *
 *  RETURNS    : A handle to the palette.                                   *
 *                                                                          *
 ****************************************************************************/
HPALETTE CreateDibPalette (hbi)
HANDLE hbi;
{
    HPALETTE hpal;

    if (!hbi)
        return NULL;
    hpal = CreateBIPalette((LPBITMAPINFOHEADER)GlobalLock(hbi));
    GlobalUnlock(hbi);
    return hpal;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   :OpenDIB(LPSTR szFile)                                       *
 *                                                                          *
 *  PURPOSE    :Open a DIB file and create a MEMORY DIB, a memory handle    *
 *              containing BITMAPINFO, palette data and the bits.           *
 *                                                                          *
 *  RETURNS    :A handle to the DIB.                                        *
 *                                                                          *
 ****************************************************************************/
HANDLE OpenDIB (szFile)
LPSTR szFile;
{
    unsigned            fh;
    BITMAPINFOHEADER    bi;
    LPBITMAPINFOHEADER  lpbi;
    DWORD               dwLen = 0;
    DWORD               dwBits;
    HANDLE              hdib;
    HANDLE              h;
    OFSTRUCT            of;

    /* Open the file and read the DIB information */
    fh = OpenFile(szFile, &of, OF_READ);
    if (fh == -1)
        return NULL;

    hdib = ReadDibBitmapInfo(fh);
    if (!hdib)
        return NULL;
    DibInfo(hdib,&bi);

    /* Calculate the memory needed to hold the DIB */
    dwBits = bi.biSizeImage;
    dwLen  = bi.biSize + (DWORD)PaletteSize (&bi) + dwBits;

    /* Try to increase the size of the bitmap info. buffer to hold the DIB */
    h = GlobalReAlloc(hdib, dwLen, GHND);
    if (!h){
        GlobalFree(hdib);
        hdib = NULL;
    }
    else
        hdib = h;

    /* Read in the bits */
    if (hdib){

        lpbi = (VOID FAR *)GlobalLock(hdib);
        lread(fh, (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi), dwBits);
        GlobalUnlock(hdib);
    }
    _lclose(fh);

    return hdib;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : BitmapFromDib(HANDLE hdib, HPALETTE hpal)                  *
 *                                                                          *
 *  PURPOSE    : Will create a DDB (Device Dependent Bitmap) given a global *
 *               handle to a memory block in CF_DIB format                  *
 *                                                                          *
 *  RETURNS    : A handle to the DDB.                                       *
 *                                                                          *
 ****************************************************************************/
HBITMAP BitmapFromDib (hdib, hpal)
HANDLE     hdib;
HPALETTE   hpal;
{
    LPBITMAPINFOHEADER  lpbi;
    HPALETTE            hpalT;
    HDC                 hdc;
    HBITMAP             hbm;

    StartWait();

    if (!hdib)
        return NULL;

    lpbi = (VOID FAR *)GlobalLock(hdib);

    if (!lpbi)
        return NULL;

    hdc = GetDC(NULL);
    if (fDoDIC)
    {	EnableICM(hdc,TRUE);
	if (hcurColorSpace) SetColorSpace(hdc, hcurColorSpace);
	SetGamutMatchingMethod(hdc,GamutMethod);
    }

    if (hpal){
        hpalT = SelectPalette(hdc,hpal,FALSE);
	RealizePalette(hdc);	 // GDI Bug...????
    }

    hbm = CreateDIBitmap(hdc,
                (LPBITMAPINFOHEADER)lpbi,
                (LONG)CBM_INIT,
                (LPSTR)lpbi + lpbi->biSize + PaletteSize(lpbi),
                (LPBITMAPINFO)lpbi,
                DIB_RGB_COLORS );

    if (hpal)
        SelectPalette(hdc,hpalT,FALSE);

    if (fDoDIC) EnableICM(hdc,FALSE);
    ReleaseDC(NULL,hdc);
    GlobalUnlock(hdib);

    EndWait();

    return hbm;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   :  DIBPaint(HDC hDC, int x, int y)			    *
 *                                                                          *
 *  PURPOSE    :  Sets the DIB/bitmap bits on the screen or the given device*
 *                                                                          *
 ****************************************************************************/
void DIBPaint (hDC, xoffset, yoffset)

HDC hDC;
int xoffset, yoffset;
{
    HPALETTE hpalT;
    BITMAPINFOHEADER bi;
    LPBITMAPINFOHEADER lpbi;
    HANDLE hdib;
    BITMAP bm;
    HBITMAP hbm;
    HBITMAP hbmgetset;
    DWORD FAR *lpb1;
    DWORD FAR *lpb2;
    BYTE FAR *lpb3;
    BYTE FAR *lpb4;
    DWORD i,j;

    if (f8BitDIB)
    {
	hdib = hdib8Bit;
	hbm  = hbm8Bit;
    }
    else
    {
	hdib = hdib24Bit;
	hbm  = hbm24Bit;
    }

    if (fCheckGamut)
	{
	if (!(f8BitDIB))
	    {
	    lpb1 = (DWORD FAR *)GlobalLock(hdib24Bit);
	    lpb2 = (DWORD FAR *)GlobalLock(hTempBits);
	    lpbi = (LPBITMAPINFOHEADER)lpb1;
	    j = (DWORD)lpbi->biWidth * lpbi->biHeight;
	    lpb1 = (DWORD FAR *)((DWORD)lpb1 + sizeof(BITMAPINFOHEADER));
	    lpb3 = (BYTE FAR *)((DWORD)lpb2 + (GlobalSize(hTempBits)*2/3));
	    lpb2 = (DWORD FAR *)((DWORD)lpb2 + sizeof(BITMAPINFOHEADER));
	    CheckColorsInGamut(hDC, lpb1, lpb3, j);
	    for (i=0; i < j; i++)
		{
		*lpb2++ = ((*lpb3++ == 1) ? *lpb1 : 0x00000000 );
		lpb1 = (DWORD FAR *)(DWORD)lpb1 + 3;
		lpb2 = (DWORD FAR *)(DWORD)lpb2 - 1;
		}
	    GlobalUnlock(hdib24Bit);
	    GlobalUnlock(hTempBits);
	    hdib = hTempBits;
	    }
	}

    hpalT = SelectPalette (hDC, hpalCurrent, FALSE);
    RealizePalette (hDC);

    DrawBitmap (hDC, xoffset, yoffset, hbm, SRCCOPY);
    yoffset = yoffset + 55;

    CreateandDrawBitmap (hDC, xoffset, yoffset, hdib, SRCCOPY);
    yoffset = yoffset + 55;

    DibInfo (hdib, &bi);
    DibBlt (hDC,
	    xoffset,
	    yoffset,
	    (int)bi.biWidth,
	    (int)bi.biHeight,
	    hdib,
	    0,
	    0,
	    SRCCOPY);
    yoffset = yoffset + 55;

    DibStrBlt (hDC,
	       xoffset,
	       yoffset,
	       (int)bi.biWidth,
	       (int)bi.biHeight,
	       hdib,
	       0,
	       0,
	       SRCCOPY);

    yoffset = yoffset + 55;

/* Test to make sure that Get/Set pairs make sense, that is, that the
   image colors do not change. */


    GetObject(hbm,sizeof(BITMAP),(LPSTR)&bm);
    hbmgetset = CreateBitmap(bm.bmWidth,
			     bm.bmHeight,
			     bm.bmPlanes,
			     bm.bmBitsPixel,
			     NULL);
    hbmgetset = SelectObject(hdcCompat,hbmgetset);
    BitBlt(hdcCompat,0,0,bm.bmWidth,bm.bmHeight,hDC,xoffset,yoffset-100,SRCCOPY);
    hbmgetset = SelectObject(hdcCompat,hbmgetset);
    lpb3 = (BYTE FAR *)GlobalLock(hdib);
    lpb4 = (BYTE FAR *)GlobalLock(hTempBits);
    lpbi = (LPBITMAPINFOHEADER)lpb4;
    for (i=0; i < sizeof(BITMAPINFOHEADER); i++)
	*lpb4++ = *lpb3++;
    if (f8BitDIB)
    {
	lpb1=(DWORD FAR *)lpb4;
	for (i=0; i < 1024; i++)
	    *lpb4++ = *lpb3++;
//	  lpb4=(BYTE FAR *)lpb1;

    }
    GetDIBits(hdcCompat, hbmgetset, 0, (int)bi.biHeight, lpb4, (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
    DibBlt (hDC,
       xoffset,
       yoffset,
       (int)bi.biWidth,
       (int)bi.biHeight,
       hTempBits,
       0,
       0,
       SRCCOPY);

    SelectPalette(hDC,hpalT,FALSE);

}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : DrawBitmap(HDC hdc, int x, int y, HBITMAP hbm, DWORD rop)  *
 *                                                                          *
 *  PURPOSE    : Draws bitmap <hbm> at the specifed position in DC <hdc>    *
 *                                                                          *
 *  RETURNS    : Return value of BitBlt()                                   *
 *                                                                          *
 ****************************************************************************/
BOOL DrawBitmap (hdc, x, y, hbm, rop)
HDC        hdc;
int        x, y;
HBITMAP    hbm;
DWORD      rop;
{
    HDC       hdcBits;
    BITMAP    bm;
    BOOL      f;

    if (!hdc || !hbm)
        return FALSE;

    hdcBits = CreateCompatibleDC(hdc);
    GetObject(hbm,sizeof(BITMAP),(LPSTR)&bm);
    SelectObject(hdcBits,hbm);
    f = BitBlt(hdc,x,y,bm.bmWidth,bm.bmHeight,hdcBits,0,0,rop);
    DeleteDC(hdcBits);

    return f;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : DibBlt( HDC hdc,                                           *
 *                       int x0, int y0,                                    *
 *                       int dx, int dy,                                    *
 *                       HANDLE hdib,                                       *
 *                       int x1, int y1,                                    *
 *                       LONG rop)                                          *
 *                                                                          *
 *  PURPOSE    : Draws a bitmap in CF_DIB format, using SetDIBitsToDevice.  *
 *               taking the same parameters as BitBlt().                    *
 *                                                                          *
 *  RETURNS    : TRUE  - if function succeeds.                              *
 *               FALSE - otherwise.                                         *
 *                                                                          *
 ****************************************************************************/
BOOL DibBlt (hdc, x0, y0, dx, dy, hdib, x1, y1, rop)
HDC        hdc;
int        x0, y0, dx, dy;
HANDLE     hdib;
int        x1, y1;
LONG       rop;
{
    LPBITMAPINFOHEADER   lpbi;
    LPSTR                pBuf;

    if (!hdib)
        return PatBlt(hdc,x0,y0,dx,dy,rop);

    lpbi = (VOID FAR *)GlobalLock(hdib);

    if (!lpbi)
        return FALSE;

    pBuf = (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi);
    SetDIBitsToDevice (hdc, x0, y0, dx, dy,
                       x1,y1,
                       x1,
                       dy,
                       pBuf, (LPBITMAPINFO)lpbi,
                       DIB_RGB_COLORS );

    GlobalUnlock(hdib);
    return TRUE;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : DibStrBlt( HDC hdc,					    *
 *			    int x0, int y0,				    *
 *			    int dx, int dy,				    *
 *			    HANDLE hdib,				    *
 *			    int x1, int y1,				    *
 *			    LONG rop)					    *
 *                                                                          *
 *  PURPOSE    : Draws a bitmap in CF_DIB format, using SetDIBits to device.*
 *               taking the same parameters as BitBlt().                    *
 *                                                                          *
 *  RETURNS    : TRUE  - if function succeeds.                              *
 *               FALSE - otherwise.                                         *
 *                                                                          *
 ****************************************************************************/
BOOL DibStrBlt (hdc, x0, y0, dx, dy, hdib, x1, y1, rop)
HDC        hdc;
int        x0, y0, dx, dy;
HANDLE     hdib;
int        x1, y1;
LONG       rop;
{
    LPBITMAPINFOHEADER   lpbi;
    LPSTR                pBuf;

    if (!hdib)
        return PatBlt(hdc,x0,y0,dx,dy,rop);

    lpbi = (VOID FAR *)GlobalLock(hdib);

    if (!lpbi)
        return FALSE;

    pBuf = (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi);
    StretchDIBits(hdc, x0, y0, dx, dy,
		       x1,y1 + dy/2,
		       dx,
		       dy / 2,
                       pBuf, (LPBITMAPINFO)lpbi,
		       DIB_RGB_COLORS,
		       rop );

    GlobalUnlock(hdib);
    return TRUE;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : CreateandDrawBitmap(HDC hdc,				    *
 *				     int x,				    *
 *				     int y,				    *
 *				     HBITMAP hbm,			    *
 *				     DWORD rop) 			    *
 *                                                                          *
 *  PURPOSE    : Draws bitmap <hbm> at the specifed position in DC <hdc>    *
 *                                                                          *
 *  RETURNS    : Return value of BitBlt()                                   *
 *                                                                          *
 ****************************************************************************/
BOOL CreateandDrawBitmap (hdc, x, y, hdib, rop)
HDC	hdc;
int	x, y;
HANDLE	hdib;
DWORD	rop;
{
    HDC       hdcBits;
    HBITMAP   hbm;
    BITMAP    bm;
    BOOL      f;

    /*	Get a DDB from the DIB */

    hbm = BitmapFromDib(hdib,hpalCurrent);
    if (!hbm) return FALSE;

    hdcBits = CreateCompatibleDC(hdc);
    GetObject(hbm,sizeof(BITMAP),(LPSTR)&bm);
    SelectObject(hdcBits,hbm);
    f = BitBlt(hdc,x,y,bm.bmWidth,bm.bmHeight,hdcBits,0,0,rop);
    DeleteDC(hdcBits);
    DeleteObject(hbm);

    return f;
}




/****************************************************************************
 *                                                                          *
 *  FUNCTION   : DibNumColors(VOID FAR * pv)                                *
 *                                                                          *
 *  PURPOSE    : Determines the number of colors in the DIB by looking at   *
 *               the BitCount filed in the info block.                      *
 *                                                                          *
 *  RETURNS    : The number of colors in the DIB.                           *
 *                                                                          *
 ****************************************************************************/
WORD DibNumColors (pv)
VOID FAR * pv;
{
    int                 bits;
    LPBITMAPINFOHEADER  lpbi;
    LPBITMAPCOREHEADER  lpbc;

    lpbi = ((LPBITMAPINFOHEADER)pv);
    lpbc = ((LPBITMAPCOREHEADER)pv);

    /*  With the BITMAPINFO format headers, the size of the palette
     *  is in biClrUsed, whereas in the BITMAPCORE - style headers, it
     *  is dependent on the bits per pixel ( = 2 raised to the power of
     *  bits/pixel).
     */
    if (lpbi->biSize != sizeof(BITMAPCOREHEADER)){
        if (lpbi->biClrUsed != 0)
            return (WORD)lpbi->biClrUsed;
        bits = lpbi->biBitCount;
    }
    else
        bits = lpbc->bcBitCount;

    switch (bits){
        case 1:
                return 2;
        case 4:
                return 16;
        case 8:
                return 256;
        default:
                /* A 24 bitcount DIB has no color table */
                return 0;
    }
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   :  PaletteSize(VOID FAR * pv)                                *
 *                                                                          *
 *  PURPOSE    :  Calculates the palette size in bytes. If the info. block  *
 *                is of the BITMAPCOREHEADER type, the number of colors is  *
 *                multiplied by 3 to give the palette size, otherwise the   *
 *                number of colors is multiplied by 4.                                                          *
 *                                                                          *
 *  RETURNS    :  Palette size in number of bytes.                          *
 *                                                                          *
 ****************************************************************************/
WORD PaletteSize (pv)
VOID FAR * pv;
{
    LPBITMAPINFOHEADER lpbi;
    WORD               NumColors;

    lpbi      = (LPBITMAPINFOHEADER)pv;
    NumColors = DibNumColors(lpbi);

    if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
        return NumColors * sizeof(RGBTRIPLE);
    else
        return NumColors * sizeof(RGBQUAD);
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : DibInfo(HANDLE hbi,LPBITMAPINFOHEADER lpbi)                *
 *                                                                          *
 *  PURPOSE    : Retrieves the DIB info associated with a CF_DIB            *
 *               format memory block.                                       *
 *                                                                          *
 *  RETURNS    : TRUE  - if successful.                                     *
 *               FALSE - otherwise                                          *
 *                                                                          *
 ****************************************************************************/
BOOL DibInfo (hbi, lpbi)
HANDLE hbi;
LPBITMAPINFOHEADER lpbi;
{
    if (hbi){
        *lpbi = *(LPBITMAPINFOHEADER)GlobalLock (hbi);

        /* fill in the default fields */
        if (lpbi->biSize != sizeof (BITMAPCOREHEADER)){
            if (lpbi->biSizeImage == 0L)
                lpbi->biSizeImage =
                    WIDTHBYTES(lpbi->biWidth*lpbi->biBitCount) * lpbi->biHeight;

            if (lpbi->biClrUsed == 0L)
                lpbi->biClrUsed = DibNumColors (lpbi);
        }
        GlobalUnlock (hbi);
        return TRUE;
    }
    return FALSE;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : FreeDibs(void) 					    *
 *                                                                          *
 *  PURPOSE    : Frees all currently active bitmap, DIB and palette objects *
 *               and initializes their handles.                             *
 *                                                                          *
 ****************************************************************************/
void FreeDibs(void)
{
    if (hpalCurrent)
        DeleteObject(hpalCurrent);

    if (hbm8Bit)
	DeleteObject(hbm8Bit);

    if (hdib8Bit)
	GlobalFree(hdib8Bit);

    if (hbi8Bit && hbi8Bit != hdib8Bit)
	GlobalFree(hbi8Bit);

    hpalCurrent = NULL;
    hdib8Bit = NULL;
    hbm8Bit  = NULL;
    hbi8Bit  = NULL;
    SetRectEmpty (&rcClip);
}



 /************* PRIVATE ROUTINES TO READ/WRITE MORE THAN 64K ***************/
/****************************************************************************
 *                                                                          *
 *  FUNCTION   : lread(int fh, VOID FAR *pv, DWORD ul)                      *
 *                                                                          *
 *  PURPOSE    : Reads data in steps of 32k till all the data has been read.*
 *                                                                          *
 *  RETURNS    : 0 - If read did not proceed correctly.                     *
 *               number of bytes read otherwise.                            *
 *                                                                          *
 ****************************************************************************/
DWORD PASCAL lread (fh, pv, ul)
int           fh;
VOID far      *pv;
DWORD         ul;
{
    DWORD     ulT = ul;
    BYTE huge *hp = pv;

    while (ul > (DWORD)MAXREAD) {
        if (_lread(fh, (LPSTR)hp, (WORD)MAXREAD) != MAXREAD)
                return 0;
        ul -= MAXREAD;
        hp += MAXREAD;
    }
    if (_lread(fh, (LPSTR)hp, (WORD)ul) != (WORD)ul)
        return 0;
    return ulT;
}
