/*-----------------------------------------------------------------------
|
|   CTL3D
|
|       Copyright Microsoft Corporation 1992.  All Rights Reserved.
|
|
|   This module contains the functions to give windows controls a 3d effect
|
|   This source is made public for your edification and debugging pleasure
|
|   PLEASE do not make any changes or release private versions of this DLL
|       send e-mail to me (wesc) if you have feature requests or bug fixes.
|
|   Thanks -- Wes.
|
|
|   History:
|       1-Jan-92 :  Added OOM handling on GetDC (not really necessary but
|                       XL4 OOM failure testing made GetDC return NULL)
|
|       1-Jan-92    :   Check wasn't getting redrawn when state changed in
|                       the default button proc.
|
|       29-Jan-92:  If button has the focus and app is switched in, we weren't
|                       redrawing the entire button check & text.  Force redraw
|                       of these on WM_SETFOCUS message.
|
|        3-Feb-92:  Fixed switch in via task manager by erasing the buttons
|                       backgound on WM_SETFOCUS (detect this when wParam == NULL)
|
|        4-Apr-92:  Make it work with OWNERDRAW buttons
|
|       22-Apr-92:  Removed Excel specific code
|
|       19-May-92:  Turn it into a DLL
|
|       May-Jun92:  Lots o' fixes & enhancements
|
|       23-Jun-92:  Added support for hiding, sizing & moving
|
|       24-Jun-92:  Make checks & radio button circles draw w/ window
|                       text color 'cause they are drawn on window bkgnd
|
|       30-Jun-92:  (0.984) Fix bug where EnableWindow of StaticText doesn't 
|                       redraw properly.  Also disable ctl3d when verWindows > 3.1
|
|      1-Jul-92:  Added WIN32 support (davegi) (not in this source)
|
|       2-Jul-92:  (0.984) Disable when verWindows >= 4.0
|
|       20-Jul-92:  (0.985) Draw focus rects of checks/radios properly on non
|                       default sized controls.
|
|       21-Jul-92:  (0.990) Ctl3dAutoSubclass
|
|       21-Jul-92:  (0.991) ported DaveGi's WIN32 support
|
|       22-Jul-92:  (0.991) fixed Ctl3dCtlColor returning fFalse bug
|
|        4-Aug-92:  (0.992) Graphic designers bug fixes...Now subclass
|                       regular buttons + disabled states for checks & radios
|
|        6-Aug-92:  (0.993) Fix bug where activate via taskman & group
|                       box has focus, & not centering text in buttons
|
|        6-Aug-92:  (0.993) Tweek drawing next to scroll bars. 
|
|       13-Aug-92:  (0.994) Fix button focus rect bug drawing due to 
|                       Win 3.0 DrawText bug.
|
|       14-Aug-92:  (1.0) Release of version 1.0
|                       Don't draw default button border on BS_DEFPUSHBUTTON
|                       pushbuttons
|                       Fix bogus bug where Windows hangs when in a AUTORADIOBUTTON
|                       hold down space bar and hit arrow key. 
|
|       23-Sep-92:  (1.01) Made Ctl3dCtlColor call DefWindowProc so it works when
|                       called in a windproc.
|
|       28-Sep-92:  (1.02) Added MyGetTextExtent so '&''s not considered in 
|                       text extents.
|
|       08-Dec-92:  (1.03) minor tweeks to the button text centering code
|                       for Publisher
|
|       11-Dec-92:  (1.04) added 3d frames to dialogs
|
|       15-Dec-92:  (1.05) fixed bug where group boxes redraw wrong when
|                       Window text is changed to something shorter
|
|       ??-Dec-92:  (1.06) added 3d borders
|
|       21-Dec-92:  (1.07) added WM_DLGBORDER to disable borders
|
|      4-Jan-93:  (1.08) fixed WM_SETTEXT bug w/ DLG frames & checks/checkboxes
|                       Also, WM_DLGSUBCLASS
|
|       22-Feb-93:  (1.12) disabled it under Chicago
|
|       25-Feb-93:  (1.13) re-add fix which allows dialog procs to
|                       handle WM_CTLCOLOR messages
|
|		26-April-93 (2.0) Changed to allow for second subclass. Now uses class instead of
|						  wndproc for subclass determination.
|						  store next wndproc in properties with global atoms						 
|
|		06-Jun-93  (2.0) Make a static linked library version.
|
|
-----------------------------------------------------------------------*/
#define NO_STRICT
#include <windows.h>

#ifdef _BORLAND
#include <mem.h>
#else
#include <memory.h>
#endif

#include <malloc.h>
#include "ctl3d.h"

#include "stdio.h"

/*-----------------------------------------------------------------------
|CTL3D Types
-----------------------------------------------------------------------*/
#ifdef WIN32

#define Win32Only(e) e
#define Win16Only(e)
#define Win32Or16(e32, e16) e32
#define Win16Or32(e16, e32) e32

#define _loadds
#define __export

#define FValidLibHandle(hlib) ((hlib) != NULL)

//
// No concept of far in Win32.
//

#define MEMCMP	memcmp
#define	NPTSTR	LPTSTR

//
// Control IDs are LONG in Win32.
//

typedef LONG CTLID;
#define GetControlId(hwnd) GetWindowLong(hwnd, GWL_ID)

//
// Send a color button message.
//

#define SEND_COLOR_BUTTON_MESSAGE( hwndParent, hwnd, hdc )      \
    ((HBRUSH) SendMessage(hwndParent, WM_CTLCOLORBTN, (WPARAM) hdc, (LPARAM) hwnd))

//
// Send a color static message.
//

#define SEND_COLOR_STATIC_MESSAGE( hwndParent, hwnd, hdc )      \
    ((HBRUSH) SendMessage(hwndParent, WM_CTLCOLORSTATIC, (WPARAM) hdc, (LPARAM) hwnd))

#else

#define CallWindowProcA  CallWindowProc
#define DefWindowProcA	DefWindowProc
#define MessageBoxA MessageBox

#define TEXT(a)  a
#define TCHAR    char

#ifndef LPTSTR
#define LPTSTR	 LPSTR
#endif
#define LPCTSTR  LPCSTR
#define	NPTSTR	 NPSTR

#define Win32Only(e)
#define Win16Only(e) e
#define Win32Or16(e32, e16) e16
#define Win16Or32(e16, e32) e16


#define FValidLibHandle(hlib) (( hlib ) > 32 )

#define MEMCMP _fmemcmp

typedef WORD CTLID;
#define GetControlId(h) GetWindowWord(h, GWW_ID)

#define SEND_COLOR_BUTTON_MESSAGE( hwndParent, hwnd, hdc )      \
    ((HBRUSH) SendMessage(hwndParent, WM_CTLCOLOR, (WORD) hdc, MAKELONG(hwnd, CTLCOLOR_BTN)))

#define SEND_COLOR_STATIC_MESSAGE( hwndParent, hwnd, hdc )      \
    ((HBRUSH) SendMessage(hwndParent, WM_CTLCOLOR, (WORD) hdc, MAKELONG(hwnd, CTLCOLOR_STATIC)))


typedef struct
	{
	LPARAM lParam;
	WPARAM wParam;
	UINT   message;
	HWND   hwnd;
} CWPSTRUCT;

#endif // WIN32

// DBCS far east short cut key support
#define cchShortCutModeMax 10
#define chShortCutSbcsPrefix '\036'
#define chShortCutDbcsPrefix '\037'

#define cchClassMax 16	// max class is "combolbox"+NUL rounded up to 16


#define Assert(f)

#define PUBLIC
#define PRIVATE static

#define fFalse 0
#define fTrue 1

#define INCBTHOOK	  1
#define OUTCBTHOOK	  0

#ifdef _BORLAND
#define CSCONST(type) type const
#define CodeLpszDecl(lpszVar, szLit) TCHAR *lpszVar = szLit
#define CodeLpszDeclA(lpszVar, szLit) char *lpszVar = szLit
#define _alloca alloca
#define _memcmp memcmp
#else
#ifdef WIN32
#define CSCONST(type) type const
#define CodeLpszDecl(lpszVar, szLit) TCHAR *lpszVar = szLit
#define CodeLpszDeclA(lpszVar, szLit) char *lpszVar = szLit
#else
#define CSCONST(type) type _based(_segname("_CODE")) const
#define CodeLpszDecl(lpszVar, szLit) \
	static CSCONST(char) lpszVar##Code[] = szLit; \
	char far *lpszVar = (char far *)lpszVar##Code
#define CodeLpszDeclA(lpszVar, szLit) \
	static CSCONST(char) lpszVar##Code[] = szLit; \
	char far *lpszVar = (char far *)lpszVar##Code
#endif
#endif


// isomorphic to windows RECT
typedef struct
    {
    int xLeft;
    int yTop;
	int xRight;
    int yBot;
    } RC;


// Windows Versions (Byte order flipped from GetWindowsVersion)
#define ver30  0x0300
#define ver31  0x030a
#define ver40  0x035F

// Border widths
#define dxBorder 1
#define dyBorder 1


// Index Color Table
// WARNING: change mpicvSysColors if you change the icv order
typedef WORD ICV;
#define icvBtnHilite 0
#define icvBtnFace 1
#define icvBtnShadow 2

#define icvBrushMax 3

#define icvBtnText 3
#define icvWindow 4
#define icvWindowText 5
#define icvGrayText 6
#define icvWindowFrame 7
#define icvMax 8

typedef COLORREF CV;

// CoLoR Table
typedef struct
    {
    CV rgcv[icvMax];
    } CLRT;


// BRush Table
typedef struct
    {
    HBRUSH mpicvhbr[icvBrushMax];
    } BRT;


// DrawRec3d flags
#define dr3Left  0x0001
#define dr3Top   0x0002
#define dr3Right 0x0004
#define dr3Bot   0x0008

#define dr3HackBotRight 0x1000  // code size is more important than aesthetics
#define dr3All    0x000f
typedef WORD DR3;


// Control Types
// Commdlg types are necessary because commdlg.dll subclasses certain 
// controls before the app can call Ctl3dSubclassDlg.
#define ctButton			0
#define ctList				1
#define ctEdit				2
#define ctCombo				3
#define ctStatic			4
#define ctComboLBox 		5
#define ctMax				6

// ConTroL 
typedef struct 
    {
    FARPROC lpfn;
    WNDPROC lpfnDefProc;
	TCHAR	szClassName[cchClassMax];
    } CTL;

// Control DEFinition
typedef struct 
    {
	TCHAR sz[20];
    WNDPROC lpfnWndProc;
	BOOL (* lpfnFCanSubclass)(HWND, LONG, WORD, WORD, HWND);
    WORD msk;
    } CDEF;

// CLIent HooK
typedef struct
    {
    HANDLE hinstApp;
    HANDLE htask;
	HHOOK  hhook;
	int    iCount;
	DWORD  dwFlags;

	} CLIHK;

#ifdef WIN32
#define iclihkMaxBig	1024
#define iclihkMaxSmall	128
#else
#define iclihkMaxBig	32
#define iclihkMaxSmall	4
#endif

#ifdef DLL
#define iclihkMax iclihkMaxBig
#else
#ifdef SDLL
#define iclihkMax iclihkMaxBig
#else
#define iclihkMax iclihkMaxSmall
#define _loadds
#endif
#endif

#ifdef SDLL
extern const HINSTANCE _hModule;
#endif

// special styles
// #define bitFCoolButtons 0x0001

/*-----------------------------------------------------------------------
|CTL3D Function Prototypes
-----------------------------------------------------------------------*/
PRIVATE VOID End3dDialogs(VOID);
PRIVATE BOOL FAR FInit3dDialogs(VOID);
PRIVATE BOOL DoSubclassCtl(HWND hwnd, WORD grbit, WORD wCallFlags, HWND hwndParent);
PRIVATE BOOL InternalCtl3dColorChange(BOOL fForce);
PRIVATE VOID DeleteObjectNull(HANDLE FAR *ph);
PRIVATE VOID DeleteObjects(VOID);
PRIVATE int  IclihkFromHinst(HANDLE hinst);

LRESULT __export _loadds WINAPI Ctl3dHook(int code, WPARAM wParam, LPARAM lParam);
LRESULT __export _loadds WINAPI BtnWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
LRESULT __export _loadds WINAPI EditWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
LRESULT __export _loadds WINAPI ListWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
LRESULT __export _loadds WINAPI ComboWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
LRESULT __export _loadds WINAPI StaticWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
LRESULT __export _loadds WINAPI CDListWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
LRESULT __export _loadds WINAPI CDEditWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
WORD	__export _loadds WINAPI Ctl3dSetStyle(HANDLE hinst, LPTSTR lpszName, WORD grbit);

LRESULT __export _loadds WINAPI Ctl3dDlgProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);

BOOL FBtn(HWND, LONG, WORD, WORD, HWND);
BOOL FEdit(HWND, LONG, WORD, WORD, HWND);
BOOL FList(HWND, LONG, WORD, WORD, HWND);
BOOL FComboList(HWND, LONG, WORD, WORD, HWND);
BOOL FCombo(HWND, LONG, WORD, WORD, HWND);
BOOL FStatic(HWND, LONG, WORD, WORD, HWND);

HBITMAP PASCAL LoadUIBitmap(HANDLE, LPCTSTR, COLORREF, COLORREF, COLORREF, COLORREF, COLORREF, COLORREF);

#ifdef WIN32
#ifdef DLL
BOOL CALLBACK LibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved);
#else
#ifdef SDLL
FAR BOOL Ctl3dLibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved);
#else
FAR BOOL LibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved);
#endif
#endif
#else
#ifdef DLL
int WINAPI LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine);
#else
#ifdef SDLL
int FAR Ctl3dLibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine);
#else
#ifdef _BORLAND
int FAR PASCAL LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine);
#else
int FAR LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine);
#endif
#endif
#endif
#endif

#ifndef _BORLAND
#ifndef WIN32
#pragma alloc_text(INIT_TEXT, Ctl3dSetStyle)
#pragma alloc_text(INIT_TEXT, Ctl3dColorChange)
#pragma alloc_text(INIT_TEXT, Ctl3dGetVer)
#pragma alloc_text(INIT_TEXT, Ctl3dRegister)
#pragma alloc_text(INIT_TEXT, Ctl3dUnregister)
#pragma alloc_text(INIT_TEXT, Ctl3dAutoSubclass)
#pragma alloc_text(INIT_TEXT, Ctl3dEnabled)
#pragma alloc_text(INIT_TEXT, Ctl3dWinIniChange)
#pragma alloc_text(INIT_TEXT, DeleteObjects)
#pragma alloc_text(INIT_TEXT, DeleteObjectNull)
#pragma alloc_text(INIT_TEXT, InternalCtl3dColorChange)
#ifdef SDLL
#pragma alloc_text(INIT_TEXT, Ctl3dLibMain)
#else
#pragma alloc_text(INIT_TEXT, LibMain)
#endif
#pragma alloc_text(INIT_TEXT, FInit3dDialogs)
#pragma alloc_text(INIT_TEXT, End3dDialogs)
#pragma alloc_text(INIT_TEXT, LoadUIBitmap)
#pragma alloc_text(INIT_TEXT, IclihkFromHinst)
#endif
#endif

#ifndef WIN32
#ifdef DLL
int FAR PASCAL WEP(int);
#pragma alloc_text(WEP_TEXT, WEP)
#endif
#endif

/*-----------------------------------------------------------------------
|CTL3D Globals
-----------------------------------------------------------------------*/
//These static varables are only access when running 16 bit Windows or Win32s
//Since this is single threaded access they are OK to be statics and not protected.
//
static HHOOK	hhookCallWndProcFilterProc;
static FARPROC	lpfnSubclassByHook;
static HWND 	SubclasshWnd;

#ifdef WIN32
CRITICAL_SECTION g_CriticalSection;
#endif

typedef struct _g3d
	{
	BOOL f3dDialogs;
	int cInited;
	ATOM aCtl3dOld;
	ATOM aCtl3dHighOld;
	ATOM aCtl3dLowOld;
	ATOM aCtl3d;
	ATOM aCtl3dHigh;
	ATOM aCtl3dLow;

	ATOM aCtl3dDisable;
	// module & windows stuff
	HANDLE hinstLib;
	HANDLE hmodLib;
	WORD   verWindows;
	WORD   verBase;

	// drawing globals
	CLRT clrt;
	BRT brt;
	HBITMAP hbmpCheckboxes;

	// Hook cache
	HANDLE htaskCache;
	int iclihkCache;
	int iclihkMac;
	CLIHK rgclihk[iclihkMax];

	// Control info
	CTL mpctctl[ctMax];
	FARPROC lpfnDefDlgWndProc;

	// System Metrics
	int dxFrame;
	int dyFrame;
	int dyCaption;
	int dxSysMenu;

	// Windows functions
#ifndef WIN32
#ifdef DLL
	HHOOK (FAR PASCAL *lpfnSetWindowsHookEx)(int, HOOKPROC, HINSTANCE, HANDLE);
	LRESULT (FAR PASCAL *lpfnCallNextHookEx)(HHOOK, int, WPARAM, LPARAM);
	BOOL (FAR PASCAL *lpfnUnhookWindowsHookEx)(HHOOK);
#endif
#endif

	// DBCS stuff
	char chShortCutPrefix;
	char fDBCS;

	} G3D;

G3D g3d;


CSCONST(CDEF) mpctcdef[ctMax] =
{
	{ TEXT("Button"), BtnWndProc3d, FBtn, CTL3D_BUTTONS },
	{ TEXT("ListBox"), ListWndProc3d, FList, CTL3D_LISTBOXES },
	{ TEXT("Edit"), EditWndProc3d, FEdit, CTL3D_EDITS },
	{ TEXT("ComboBox"), ComboWndProc3d, FCombo, CTL3D_COMBOS},
	{ TEXT("Static"), StaticWndProc3d, FStatic, CTL3D_STATICTEXTS|CTL3D_STATICFRAMES },
	{ TEXT("ComboLBox"), ListWndProc3d,	FComboList, CTL3D_LISTBOXES },
};


CSCONST (WORD) mpicvSysColor[] =
	{
	COLOR_BTNHIGHLIGHT,
	COLOR_BTNFACE,
	COLOR_BTNSHADOW,
	COLOR_BTNTEXT,
	COLOR_WINDOW,
	COLOR_WINDOWTEXT,
	COLOR_GRAYTEXT,
	COLOR_WINDOWFRAME
	};

#define WM_CHECKSUBCLASS_OLD (WM_USER+5443)
#define WM_CHECKSUBCLASS (WM_USER+5444)

/*-----------------------------------------------------------------------
|   CTL3D Utility routines
-----------------------------------------------------------------------*/

PRIVATE FARPROC LpfnGetDefWndProcNull(HWND hwnd)
	{                                
	if ( hwnd == NULL ) 
		return NULL;
		
	Win32Only(return (FARPROC) GetProp(hwnd, (LPCTSTR) g3d.aCtl3d));
	Win16Only(return (FARPROC) MAKELONG((UINT) GetProp(hwnd, (LPCSTR) g3d.aCtl3dLow),
		GetProp(hwnd, (LPCSTR) g3d.aCtl3dHigh)));
	}

PRIVATE FARPROC LpfnGetDefWndProc(HWND hwnd, int ct)
        {
        FARPROC lpfnWndProc;

		lpfnWndProc = LpfnGetDefWndProcNull(hwnd);
        if ( lpfnWndProc == NULL ) {
			if ( ct == ctMax )
				{
				lpfnWndProc = (FARPROC) g3d.lpfnDefDlgWndProc;
				}
			else
				{
				lpfnWndProc = (FARPROC) g3d.mpctctl[ct].lpfnDefProc;
				}

			Win32Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3d, (HANDLE)(DWORD)lpfnWndProc));
			Win16Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow,  LOWORD(lpfnWndProc)));
			Win16Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh, HIWORD(lpfnWndProc)));
		}
        return lpfnWndProc;

        }

PRIVATE VOID SubclassWindow(HWND hwnd, FARPROC lpfnSubclassProc)
	{
	FARPROC lpfnWndProc;

	// Make sure we don't double subclass (16 | 32 bit subclass??)
	if (GetProp(hwnd, (LPCTSTR) g3d.aCtl3dOld) ||
		GetProp(hwnd, (LPCTSTR) g3d.aCtl3d) ||
		GetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow) ||
		GetProp(hwnd, (LPCTSTR) g3d.aCtl3dLowOld) ||
		GetProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh) ||
		GetProp(hwnd, (LPCTSTR) g3d.aCtl3dHighOld))
	{
		return;
	}

	// Is this already subclassed by CTL3D?
	if (LpfnGetDefWndProcNull(hwnd) == (FARPROC) NULL)
		{
#ifdef WIN32
		  if (g3d.fDBCS && !IsWindowUnicode(hwnd)) 
		  {
		    TCHAR szClass[cchClassMax];
		    GetClassName(hwnd, szClass, cchClassMax);
			if (lstrcmpi(szClass, TEXT("edit")) == 0)
			{
				lpfnWndProc = (FARPROC)SetWindowLongA(hwnd, GWL_WNDPROC,(LONG)lpfnSubclassProc);
				goto SetProps;
			}
		  }
#endif

		 lpfnWndProc = (FARPROC)SetWindowLong((HWND) hwnd, GWL_WNDPROC, (LONG) lpfnSubclassProc);
SetProps:
		 Win32Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3d, (HANDLE)(DWORD)lpfnWndProc));
		 Win16Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow,	LOWORD(lpfnWndProc)));
		 Win16Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh, HIWORD(lpfnWndProc)));
		}
	}

LRESULT __export _loadds WINAPI CallWndProcFilterProc(int code, WPARAM wParam, LPARAM lParam)
{
	CWPSTRUCT FAR *cwpStruct;
	LONG l;

	cwpStruct = (CWPSTRUCT FAR *) lParam;

	l = CallNextHookEx(hhookCallWndProcFilterProc, code, wParam, lParam);

	if ( cwpStruct->hwnd == SubclasshWnd )
		{
		BOOL fSubclass;
		UnhookWindowsHookEx(hhookCallWndProcFilterProc);

		if (g3d.verWindows >= ver40 && (GetWindowLong(cwpStruct->hwnd, GWL_STYLE) & 0x04))
			fSubclass = fFalse;
		else
			fSubclass = fTrue;
		SendMessage(cwpStruct->hwnd, WM_DLGSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);
		if (fSubclass)
			SubclassWindow(cwpStruct->hwnd, lpfnSubclassByHook);

		hhookCallWndProcFilterProc = 0L;
		lpfnSubclassByHook = NULL;
		SubclasshWnd = NULL;
		}

	return l;
}


PRIVATE VOID HookSubclassWindow(HWND hWnd, FARPROC lpfnSubclass)
{
	//
	// Windows 3.1 ( 16 bit ) and Win32s can't sublcass in
	// WH_CBT hook. Must set up a MSG hook and subclasss at
	// WM_GETMINMAXINFO ( for dialogs ) or WM_NCCREATE ( for controls )
	// Any other message and we are out of here.
	//
	// Notes from the inside:
	//
	// The only reason not to get the WM_GETMINMAXINFO/WM_NCCREATE message
	// is if another CBT hook did not allow the window create.
	// This code only runs/works on non multithreaded systems. Thus the global
	// to hold the Hook Proc and subclass proc is OK.
	//

	lpfnSubclassByHook = lpfnSubclass;
	SubclasshWnd = hWnd;

	Win32Only(hhookCallWndProcFilterProc = SetWindowsHookEx(WH_CALLWNDPROC, (FARPROC)CallWndProcFilterProc, g3d.hmodLib, GetCurrentThreadId()));
	Win16Only(hhookCallWndProcFilterProc = SetWindowsHookEx(WH_CALLWNDPROC, (FARPROC)CallWndProcFilterProc, g3d.hmodLib, GetCurrentTask()));
}

PRIVATE LRESULT CleanupSubclass(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, int ct)
	{
	FARPROC lpfnWinProc;
	LRESULT lRet;

	lpfnWinProc = LpfnGetDefWndProc(hwnd, ct);
	lRet = CallWindowProc(lpfnWinProc, hwnd, wm, wParam, lParam);
	Win32Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3d));
	Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dLow));
	Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh));
  	RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dDisable);
  	return lRet;
	}


PRIVATE VOID DeleteObjectNull(HANDLE FAR *ph)
	{
	if (*ph != NULL)
		{
		DeleteObject(*ph);
		*ph = NULL;
		}
	}

PRIVATE VOID DeleteObjects(VOID)
	{
	int icv;
	
	for(icv = 0; icv < icvBrushMax; icv++)
	    DeleteObjectNull(&g3d.brt.mpicvhbr[icv]);
	DeleteObjectNull(&g3d.hbmpCheckboxes);
	}


PRIVATE VOID PatFill(HDC hdc, RC FAR *lprc)
	{
	PatBlt(hdc, lprc->xLeft, lprc->yTop, lprc->xRight-lprc->xLeft, lprc->yBot-lprc->yTop, PATCOPY);
	}


/*-----------------------------------------------------------------------
|   DrawRec3d
|   
|   
|   Arguments:
|       HDC hdc:    
|       RC FAR *lprc:   
|       LONG cvUL:  
|       LONG cvLR:  
|       WORD grbit;
|       
|   Returns:
|       
-----------------------------------------------------------------------*/
PRIVATE VOID DrawRec3d(HDC hdc, RC FAR *lprc, ICV icvUL, ICV icvLR, DR3 dr3)
	{
	COLORREF cvSav;
	RC rc;

	cvSav = SetBkColor(hdc, g3d.clrt.rgcv[icvUL]);

	// top
	rc = *lprc;
	rc.yBot = rc.yTop+1;
	if (dr3 & dr3Top)
		ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc, 
			(LPCTSTR) NULL, 0, (int far *) NULL);

	// left
	rc.yBot = lprc->yBot;
	rc.xRight = rc.xLeft+1;
	if (dr3 & dr3Left)
	ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc, 
		(LPCTSTR) NULL, 0, (int far *) NULL);

	if (icvUL != icvLR)
		SetBkColor(hdc, g3d.clrt.rgcv[icvLR]);

	// right
	rc.xRight = lprc->xRight;
	rc.xLeft = rc.xRight-1;
	if (dr3 & dr3Right)
		ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc, 
			(LPCTSTR) NULL, 0, (int far *) NULL);

	// bot
	if (dr3 & dr3Bot)
		{
		rc.xLeft = lprc->xLeft;
		rc.yTop = rc.yBot-1;
		if (dr3 & dr3HackBotRight)
			rc.xRight -=2;
		ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc, 
			(LPCTSTR) NULL, 0, (int far *) NULL);
		}

	SetBkColor(hdc, cvSav);

	}

#ifdef CANTUSE
// Windows forces dialog fonts to be BOLD...URRRGH
PRIVATE VOID MyDrawText(HWND hwnd, HDC hdc, LPSTR lpch, int cch, RC FAR *lprc, int dt)
	{
	TEXTMETRIC tm;
	BOOL fChisled;

	fChisled = fFalse;
	if (!IsWindowEnabled(hwnd))
		{
		GetTextMetrics(hdc, &tm);
		if (tm.tmWeight > 400)
			SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);
		else
			{
			fChisled = fTrue;
			SetTextColor(hdc, g3d.clrt.rgcv[icvBtnHilite]);
			OffsetRect((LPRECT) lprc, -1, -1);
			}
		}
	DrawText(hdc, lpch, cch, (LPRECT) lprc, dt);
	if (fChisled)
		{
		SetTextColor(hdc, g3d.clrt.rgcv[icvBtnHilite]);
		OffsetRect((LPRECT) lprc, 1, 1);
		DrawText(hdc, lpch, cch, (LPRECT) lprc, dt);
		}
	}
#endif


PRIVATE VOID DrawInsetRect3d(HDC hdc, RC FAR *prc, DR3 dr3)
	{
	RC rc;

	rc = *prc;
	DrawRec3d(hdc, &rc, icvWindowFrame, icvBtnFace, (WORD)(dr3 & dr3All));
	rc.xLeft--;
	rc.yTop--;
	rc.xRight++;
	rc.yBot++;
	DrawRec3d(hdc, &rc, icvBtnShadow, icvBtnHilite, dr3);
	}


PRIVATE VOID ClipCtlDc(HWND hwnd, HDC hdc)
	{
	RC rc;

	GetClientRect(hwnd, (LPRECT) &rc);
	IntersectClipRect(hdc, rc.xLeft, rc.yTop, rc.xRight, rc.yBot);
	}


PRIVATE int IclihkFromHinst(HANDLE hinst)
	{
	int iclihk;

	for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
		if (g3d.rgclihk[iclihk].hinstApp == hinst)
			return iclihk;
	return -1;
	}


PRIVATE VOID MyGetTextExtent(HDC hdc, LPTSTR lpsz, int FAR *lpdx, int FAR *lpdy)
	{
	LPTSTR lpch;
	TCHAR  szT[256];

	lpch = szT;
	while(*lpsz != '\000')
		{
		if (*lpsz == '&')
			{
			lpsz++;
			if (*lpsz == '\000')
				break;
			}
//begin DBCS: far east short cut key support
		else if (g3d.fDBCS)
			{
			if (*lpsz == g3d.chShortCutPrefix)
				{ // skip only prefix
				lpsz++;
				if (*lpsz == '\000')
					break;
				}
			else if (*lpsz == chShortCutSbcsPrefix || *lpsz == chShortCutDbcsPrefix)
				{ // skip both prefix and short cut key
				lpsz++;
				if (*lpsz == '\000')
					break;
				lpsz = Win32Or16(CharNext(lpsz),AnsiNext(lpsz));
				continue;
				}
			}
//end DBCS
		*lpch++ = *lpsz++;
		}
	*lpch = '\000';
#ifdef WIN32
	{
	SIZE	pt;

	GetTextExtentPoint(hdc, szT, lstrlen(szT), &pt);
	*lpdx = pt.cx;
	*lpdy = pt.cy;
	}
#else
	{
	long dwExt;

	dwExt = GetTextExtent(hdc, szT, lpch-(char far *)szT);
	*lpdx = LOWORD(dwExt);
	// Check for Hangeul Windows - JeeP 011194
	if ( (g3d.verWindows >= ver31 && GetSystemMetrics(SM_DBCSENABLED)) ||
		 (IsDBCSLeadByte(0xa1) && !IsDBCSLeadByte(0xa0)) )
		*lpdy = HIWORD(dwExt)+1;
	else
		*lpdy = HIWORD(dwExt);
	}
#endif
	}
	

/*-----------------------------------------------------------------------
|   CTL3D Publics
-----------------------------------------------------------------------*/


PUBLIC BOOL WINAPI Ctl3dRegister(HANDLE hinstApp)
	{

#ifdef WIN32
#ifndef DLL
	InitializeCriticalSection(&g_CriticalSection);
#endif
	EnterCriticalSection(&g_CriticalSection);
#endif

	g3d.cInited++;

	Win32Only(LeaveCriticalSection(&g_CriticalSection));

	if (g3d.cInited == 1)
		{
#ifndef DLL
#ifdef SDLL
		Win32Only(Ctl3dLibMain(hinstApp, DLL_PROCESS_ATTACH, (LPVOID) NULL));
		Win16Only(Ctl3dLibMain(hinstApp, 0, 0, (LPSTR) NULL));
#else
		Win32Only(LibMain(hinstApp, DLL_PROCESS_ATTACH, (LPVOID) NULL));
		Win16Only(LibMain(hinstApp, 0, 0, (LPSTR) NULL));
#endif
#endif
		FInit3dDialogs();
		}

	if (Ctl3dIsAutoSubclass())
		Ctl3dAutoSubclass(hinstApp);

	return g3d.f3dDialogs;
	}


PUBLIC BOOL WINAPI Ctl3dUnregister(HANDLE hinstApp)
	{
	int iclihk;
	HANDLE hTask;

	//
	// Find the task's hook
	//
	Win32Only(hTask = (HANDLE)GetCurrentThreadId());
	Win16Only(hTask = GetCurrentTask());

	Win32Only(EnterCriticalSection(&g_CriticalSection));

	for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
		{
		if (g3d.rgclihk[iclihk].htask == hTask)
			{
			g3d.rgclihk[iclihk].iCount--;
			if ( g3d.rgclihk[iclihk].iCount == 0 || hinstApp == g3d.rgclihk[iclihk].hinstApp)
				{
				Win32Only(UnhookWindowsHookEx(g3d.rgclihk[iclihk].hhook));
#ifdef DLL
				Win16Only((*g3d.lpfnUnhookWindowsHookEx)(g3d.rgclihk[iclihk].hhook));
#else
				Win16Only(UnhookWindowsHookEx(g3d.rgclihk[iclihk].hhook));
#endif
				g3d.iclihkMac--;
				while(iclihk < g3d.iclihkMac)
					{
					g3d.rgclihk[iclihk] = g3d.rgclihk[iclihk+1];
					iclihk++;
					}
				}
			}
		}

	g3d.cInited--;

	Win32Only(LeaveCriticalSection(&g_CriticalSection));
		
	if (g3d.cInited == 0)
		{
		End3dDialogs();
		}
	return fTrue;
	}




/*-----------------------------------------------------------------------
|   Ctl3dAutoSubclass
|   
|	   Automatically subclasses all dialogs of the client app.
|
|   Note: Due to bugs in Commdlg, an app should still call Ctl3dSubclassDlg 
|   for the Commdlg OpenFile and PageSetup dialogs.
|   
|   Arguments:
|	   HANDLE hinstApp:	
|	   
|   Returns:
|	   
-----------------------------------------------------------------------*/
PUBLIC BOOL WINAPI Ctl3dAutoSubclass(HANDLE hinstApp)
{
	return Ctl3dAutoSubclassEx(hinstApp, 0);
}

PUBLIC BOOL WINAPI Ctl3dAutoSubclassEx(HANDLE hinstApp, DWORD dwFlags)
	{
	HHOOK  hhook;
	HANDLE htask;
	int    iclihk;

	if (g3d.verWindows < ver31)
		return fFalse;
	if (!g3d.f3dDialogs)
		return fFalse;

#ifdef WIN32
	// CTL3D_SUBCLASS_DYNCREATE is considered default in Win32, but
	// not Win16 for backward compatibility reasons.
	dwFlags |= CTL3D_SUBCLASS_DYNCREATE;
#endif
	// CTL3D_NOSUBCLASS_DYNCREATE always overrides CTL3D_SUBCLASS_DYNCREATE
	if (dwFlags & CTL3D_NOSUBCLASS_DYNCREATE)
		dwFlags &= ~(CTL3D_NOSUBCLASS_DYNCREATE|CTL3D_SUBCLASS_DYNCREATE);

	Win32Only(EnterCriticalSection(&g_CriticalSection));

	if (g3d.iclihkMac == iclihkMax)
		goto Fail;

	Win32Only(htask = (HANDLE)GetCurrentThreadId());
	Win16Only(htask = GetCurrentTask());
	//
	// Don't set the hook twice for the same task....
	//
	for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
		{
		if (g3d.rgclihk[iclihk].htask == htask)
			{
			g3d.rgclihk[iclihk].iCount++;
			goto Success;
			}
		}

	Win32Only(hhook = SetWindowsHookEx(WH_CBT, (HOOKPROC)Ctl3dHook, g3d.hmodLib, (DWORD)htask));
#ifdef DLL
	Win16Only(hhook = (*g3d.lpfnSetWindowsHookEx)(WH_CBT, (HOOKPROC) Ctl3dHook, g3d.hmodLib, hinstApp == NULL ? NULL : htask));
#else
	Win16Only(hhook = SetWindowsHookEx(WH_CBT, (HOOKPROC) Ctl3dHook, g3d.hmodLib, hinstApp == NULL ? NULL : htask));
#endif
	if (hhook != NULL)
		{
		g3d.rgclihk[g3d.iclihkMac].hinstApp = hinstApp;
		g3d.rgclihk[g3d.iclihkMac].htask	= htask;
		g3d.rgclihk[g3d.iclihkMac].hhook	= hhook;
		g3d.rgclihk[g3d.iclihkMac].iCount	= 1;
		g3d.rgclihk[g3d.iclihkMac].dwFlags	= dwFlags;
		g3d.htaskCache = htask;
		g3d.iclihkCache = g3d.iclihkMac;
		g3d.iclihkMac++;
Success:
		Win32Only(LeaveCriticalSection(&g_CriticalSection));
		return fTrue;
		}
Fail:
	Win32Only(LeaveCriticalSection(&g_CriticalSection));
	return fFalse;
	}

/*-----------------------------------------------------------------------
|	Ctl3dIsAutoSubclass
|   
|   Returns:
|		Whether this task has Automatic Subclassing Enabled
|       
-----------------------------------------------------------------------*/
PUBLIC BOOL WINAPI Ctl3dIsAutoSubclass()
	{
		int iclihk;
		HANDLE hTask;

		Win32Only(hTask = (HANDLE)GetCurrentThreadId());
		Win16Only(hTask = GetCurrentTask());

		for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
			{
			if (g3d.rgclihk[iclihk].htask == hTask)
				{
				return TRUE;
				}
			}
		// didn't find task in hook table.
		return FALSE;
	}

/*-----------------------------------------------------------------------
|	Ctl3dUnAutoSubclass
|   
-----------------------------------------------------------------------*/
PUBLIC BOOL WINAPI Ctl3dUnAutoSubclass()
	{
	int iclihk;
	HANDLE hTask;

	// Find the task's hook
	//
	//
	Win32Only(hTask = (HANDLE)GetCurrentThreadId());
	Win16Only(hTask = GetCurrentTask());
	Win32Only(EnterCriticalSection(&g_CriticalSection));
	for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
		{
		if (g3d.rgclihk[iclihk].htask == hTask)
			{
			g3d.rgclihk[iclihk].iCount--;
			if ( g3d.rgclihk[iclihk].iCount == 0 )
				{
				Win32Only(UnhookWindowsHookEx(g3d.rgclihk[iclihk].hhook));
#ifdef DLL
				Win16Only((*g3d.lpfnUnhookWindowsHookEx)(g3d.rgclihk[iclihk].hhook));
#else
				Win16Only(UnhookWindowsHookEx(g3d.rgclihk[iclihk].hhook));
#endif
				g3d.iclihkMac--;
				while(iclihk < g3d.iclihkMac)
					{
					g3d.rgclihk[iclihk] = g3d.rgclihk[iclihk+1];
					iclihk++;
					}
				}
			}
		}
	Win32Only(LeaveCriticalSection(&g_CriticalSection));
	return TRUE;
	}

WORD __export _loadds WINAPI Ctl3dSetStyle(HANDLE hinst, LPTSTR lpszName, WORD grbit)
	{
#ifdef OLD
	WORD grbitOld;

	if (!g3d.f3dDialogs)
		return fFalse;

	grbitOld = grbitStyle;
	if (grbit != 0)
		grbitStyle = grbit;

	if (hinst != NULL && lpszName != NULL)
		{
		HBITMAP hbmpCheckboxesNew;

		hbmpCheckboxesNew = LoadUIBitmap(hinst, (LPCSTR) lpszName,
			g3d.clrt.rgcv[icvWindowText],
			g3d.clrt.rgcv[icvBtnFace],
			g3d.clrt.rgcv[icvBtnShadow],
			g3d.clrt.rgcv[icvBtnHilite],
			g3d.clrt.rgcv[icvWindow],
			g3d.clrt.rgcv[icvWindowFrame]);
		if (hbmpCheckboxesNew != NULL)
			{
			DeleteObjectNull(&g3d.hbmpCheckboxes);
			g3d.hbmpCheckboxes = hbmpCheckboxesNew;
			}
		}
	
	return grbitOld;
#endif
	return 0;
	}


/*-----------------------------------------------------------------------
|   Ctl3dGetVer
|   
|       Returns version of CTL3D library
|   
|   Returns:
|       Major version # in hibyte, minor version # in lobyte
|       
-----------------------------------------------------------------------*/
PUBLIC WORD WINAPI Ctl3dGetVer(void)
    {
	return 0x0231;
    }


/*-----------------------------------------------------------------------
|   Ctl3dEnabled
|   
|   Returns:
|       Whether or not controls will be draw with 3d effects
-----------------------------------------------------------------------*/
PUBLIC BOOL WINAPI Ctl3dEnabled(void)
	{
	return g3d.f3dDialogs;
	}



/*-----------------------------------------------------------------------
|   Ctl3dSubclassCtl
|   
|       Subclasses an individual control
|   
|   Arguments:
|       HWND hwnd:  
|       
|   Returns:
|       fTrue if control was successfully subclassed
|       
-----------------------------------------------------------------------*/
PUBLIC BOOL WINAPI Ctl3dSubclassCtl(HWND hwnd)
	{
	if (!g3d.f3dDialogs)
		return fFalse;
	return DoSubclassCtl(hwnd, CTL3D_ALL, OUTCBTHOOK, NULL);
	}

/*-----------------------------------------------------------------------
|	Ctl3dUnsubclassCtl
|   
|		Un-Subclasses an individual control
|   
|   Arguments:
|		HWND hwnd:
|       
|   Returns:
|       fTrue if control was successfully subclassed
|       
-----------------------------------------------------------------------*/
PUBLIC BOOL WINAPI Ctl3dUnsubclassCtl(HWND hwnd)
	{
	FARPROC lpfnWinProc;
	HWND hwndKids;
	int ct;

	if (!g3d.f3dDialogs)
		return fFalse;

	lpfnWinProc = (FARPROC) GetWindowLong(hwnd, GWL_WNDPROC);

	// Is it a control
	for (ct = 0; ct < ctMax; ct++)
		{
		if ( lpfnWinProc == g3d.mpctctl[ct].lpfn )
			{
			 lpfnWinProc = LpfnGetDefWndProc(hwnd, ct);
			 Win32Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3d));
			 Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dLow));
			 Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh));
			 SetWindowLong(hwnd, GWL_WNDPROC, (LONG) lpfnWinProc );
			 lpfnWinProc = NULL;
			 ct = ctMax+10;
			}
		}

	// How about a dlg ?
	if ( ct == ctMax )
		{
		 if ( lpfnWinProc == (FARPROC) Ctl3dDlgProc )
			{
			 lpfnWinProc = LpfnGetDefWndProc(hwnd, ct);
			 Win32Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3d));
			 Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dLow));
			 Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh));
			 SetWindowLong(hwnd, GWL_WNDPROC, (LONG) lpfnWinProc );
			 lpfnWinProc = NULL;
			}
		 else
			{
			   // None of the above, add disable property
			   if (GetProp(hwnd, (LPCTSTR) g3d.aCtl3d) ||
			   	   GetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow) ||
			   	   GetProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh))
			   {
			   		SetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable, (HANDLE) 1);
			   }
			}
		}

	//
	// Now unsubclass all the kids
	//
	for (hwndKids = GetWindow(hwnd, GW_CHILD); hwndKids != NULL;
				hwndKids = GetWindow(hwndKids, GW_HWNDNEXT))
		{
			Ctl3dUnsubclassCtl(hwndKids);
		}

	return fTrue;

	}


/*-----------------------------------------------------------------------
|	Ctl3dSubclassCtlEx
|   
|	   Actually subclass the control
|   
|	   
-----------------------------------------------------------------------*/
PUBLIC BOOL WINAPI Ctl3dSubclassCtlEx(HWND hwnd, int ct)
	{
	LONG style;
	BOOL fCan;

	if (!g3d.f3dDialogs)
		return fFalse;

	if (ct < 0 || ct > ctMax)
		return fFalse;

	// Is this already subclassed by CTL3D?
	if (LpfnGetDefWndProcNull(hwnd) != (FARPROC) NULL)
	   return fFalse;

	// Only subclass it if it is something that we'd normally subclass
	style = GetWindowLong(hwnd, GWL_STYLE);
	fCan = mpctcdef[ct].lpfnFCanSubclass(hwnd, style, CTL3D_ALL,
		OUTCBTHOOK, GetParent(hwnd));
	if (fCan == fTrue)
		SubclassWindow(hwnd, g3d.mpctctl[ct].lpfn);

	return fTrue;
	}

/*-----------------------------------------------------------------------
|   Ctl3dSubclassDlg
|
|	   Call this during WM_INITDIALOG processing.
|
|   Arguments:
|	   hwndDlg:
|
-----------------------------------------------------------------------*/
PUBLIC BOOL WINAPI Ctl3dSubclassDlg(HWND hwndDlg, WORD grbit)
	{
	HWND hwnd;

	if (!g3d.f3dDialogs)
		return fFalse;

	for(hwnd = GetWindow(hwndDlg, GW_CHILD); hwnd != NULL;
		hwnd = GetWindow(hwnd, GW_HWNDNEXT))
		{
		DoSubclassCtl(hwnd, grbit, OUTCBTHOOK, NULL);
		}
	return fTrue;
	}

/*-----------------------------------------------------------------------
|	Ctl3dCheckSubclassDlg
|
|	   Call this during WM_INITDIALOG processing.
|
|   Arguments:
|	   hwndDlg:
|
-----------------------------------------------------------------------*/
PRIVATE void CheckChildSubclass(HWND hwnd, WORD grbit, HWND hwndParent)
{
	// Is this already subclassed by CTL3D?
	// Is our property there ?
	if (LpfnGetDefWndProcNull(hwnd) == (FARPROC) NULL)
		{
		// No, how did this slip by, try a subclass again.
		DoSubclassCtl(hwnd, grbit, OUTCBTHOOK, hwndParent);
		}
	else
		{
		// Yes, we have subclassed this control.
		// Is our subclass still on the chain ?
		BOOL fSubclass;

		// Make sure subclassing isn't disabled...
		if (GetProp(hwnd, (LPCTSTR)g3d.aCtl3dDisable))
			return;

		fSubclass = 666;
		SendMessage((HWND) hwnd, WM_CHECKSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);
		if ( fSubclass == 666 )
			SendMessage((HWND) hwnd, WM_CHECKSUBCLASS_OLD, 0, (LPARAM)(int FAR *)&fSubclass);

		if ( fSubclass == 666 )  // Evil
			{
			// We have been un-subclassed by some bad app ( common dialogs in Win16 )
			// Remove the Prop, and subclass again, take that.
			Win32Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3d));
			Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dLow));
			Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh));
			DoSubclassCtl(hwnd, grbit, OUTCBTHOOK, hwndParent);
			}
		}
}

PUBLIC BOOL WINAPI Ctl3dCheckSubclassDlg(HWND hwndDlg, WORD grbit)
	{
	HWND hwnd, hwnd2;

	if (!g3d.f3dDialogs)
		return fFalse;

	for (hwnd = GetWindow(hwndDlg, GW_CHILD); hwnd != NULL;
		hwnd = GetWindow(hwnd, GW_HWNDNEXT))
		{
			CheckChildSubclass(hwnd, grbit, NULL);
			for (hwnd2 = GetWindow(hwnd, GW_CHILD); hwnd2 != NULL;
				hwnd2 = GetWindow(hwnd2, GW_HWNDNEXT))
				{
					CheckChildSubclass(hwnd2, grbit, hwnd);
				}
		}

	return fTrue;
	}

/*-----------------------------------------------------------------------
|   Ctl3dSubclassDlgEx
|
|	   Call this during WM_INITDIALOG processing. This is like
|	 Ctl3dSubclassDlg but it also subclasses the dialog window itself
|	 so the app doesn't need to.
|
|   Arguments:
|	   hwndDlg:
|
-----------------------------------------------------------------------*/
PUBLIC BOOL WINAPI Ctl3dSubclassDlgEx(HWND hwndDlg, DWORD grbit)
	{
	HWND hwnd;

	if (!g3d.f3dDialogs)
		return fFalse;

	for(hwnd = GetWindow(hwndDlg, GW_CHILD); hwnd != NULL;
		hwnd = GetWindow(hwnd, GW_HWNDNEXT))
		{
		DoSubclassCtl(hwnd, LOWORD(grbit), OUTCBTHOOK, NULL);
		}

	//
	// Now Subclass the dialog window as well
	//
	SubclassWindow((HWND) hwndDlg, (FARPROC)Ctl3dDlgProc);

	return fTrue;
	}


/*-----------------------------------------------------------------------
|   Ctl3dCtlColor
|
|       Common CTL_COLOR processor for 3d UITF dialogs & alerts.
|
|   Arguments:
|       hdc:
|       lParam:
|
|   Returns:
|       appropriate brush if g3d.f3dDialogs.  Returns fFalse otherwise
|
-----------------------------------------------------------------------*/
PUBLIC HBRUSH WINAPI Ctl3dCtlColor(HDC hdc, LPARAM lParam)
	{
#ifdef WIN32
	return (HBRUSH) fFalse;
#else
	HWND hwndParent;

	Assert(CTLCOLOR_MSGBOX < CTLCOLOR_BTN);
	Assert(CTLCOLOR_EDIT < CTLCOLOR_BTN);
	Assert(CTLCOLOR_LISTBOX < CTLCOLOR_BTN);
	if(g3d.f3dDialogs)
		{
		if (HIWORD(lParam) >= CTLCOLOR_LISTBOX)
			{
			if (HIWORD(lParam) == CTLCOLOR_LISTBOX &&
				(g3d.verWindows >= ver40 ||
				((GetWindow(LOWORD(lParam), GW_CHILD) == NULL ||
				(GetWindowLong(LOWORD(lParam), GWL_STYLE) & 0x03) == CBS_DROPDOWNLIST))))
				{
				// if it doesn't have a child then it must be a list box
				// don't do brush stuff for drop down lists or else
				// it draws funny grey inside the edit rect
				goto DefWP;
				}
			SetTextColor(hdc, g3d.clrt.rgcv[icvBtnText]);
			SetBkColor(hdc, g3d.clrt.rgcv[icvBtnFace]);
			return g3d.brt.mpicvhbr[icvBtnFace];
			}
		}
DefWP:
	hwndParent = GetParent(LOWORD(lParam));
	if (hwndParent == NULL)
		return fFalse;
	return (HBRUSH) DefWindowProc(hwndParent, WM_CTLCOLOR, (WPARAM) hdc, (LONG) lParam);
#endif
	}



/*-----------------------------------------------------------------------
|   Ctl3dCtlColorEx
|
|       Common CTL_COLOR processor for 3d UITF dialogs & alerts.
|
|   Arguments:
|
|   Returns:
|       appropriate brush if g3d.f3dDialogs.  Returns fFalse otherwise
|
-----------------------------------------------------------------------*/
PUBLIC HBRUSH WINAPI Ctl3dCtlColorEx(UINT wm, WPARAM wParam, LPARAM lParam)
	{
#ifdef WIN32
	Assert(WM_CTLCOLORMSGBOX < WM_CTLCOLORBTN);
	Assert(WM_CTLCOLOREDIT < WM_CTLCOLORBTN);
	Assert(WM_CTLCOLORLISTBOX < WM_CTLCOLORBTN);
	if(g3d.f3dDialogs)
		{
		if (wm >= WM_CTLCOLORLISTBOX && wm != WM_CTLCOLORSCROLLBAR)
			{
			if (wm == WM_CTLCOLORLISTBOX &&
				(g3d.verWindows >= ver40 ||
				((GetWindow((HWND) lParam, GW_CHILD) == NULL ||
				(GetWindowLong((HWND) lParam, GWL_STYLE) & 0x03) == CBS_DROPDOWNLIST))))
				{
				// if it doesn't have a child then it must be a list box
				// don't do brush stuff for drop down lists or else
				// it draws funny grey inside the edit rect
				return (HBRUSH) fFalse;
				}
			SetTextColor((HDC) wParam, g3d.clrt.rgcv[icvBtnText]);
			SetBkColor((HDC) wParam, g3d.clrt.rgcv[icvBtnFace]);
			return g3d.brt.mpicvhbr[icvBtnFace];
			}
		}
	return (HBRUSH) fFalse;
#else
	return Ctl3dCtlColor(wParam, lParam);
#endif
	}


/*-----------------------------------------------------------------------
|   Ctl3dColorChange
|   
|	   App calls this when it gets a WM_SYSCOLORCHANGE message
|	   
|   Returns:
|	   TRUE if successful.
|	   
-----------------------------------------------------------------------*/
PUBLIC BOOL WINAPI Ctl3dColorChange(VOID)
	{
	BOOL bResult;
	Win32Only(EnterCriticalSection(&g_CriticalSection));
	bResult = InternalCtl3dColorChange(fFalse);
	Win32Only(LeaveCriticalSection(&g_CriticalSection));
	return bResult;
	}

PRIVATE LONG WINAPI
Ctl3dDlgFramePaintI(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, BOOL fDefWP);

/*-----------------------------------------------------------------------
|	Ctl3dDlgFramePaint
|   
|	   App calls this when it gets a NC_PAINT message
|	   
|   Returns:
|	   TRUE if successful.
|	   
-----------------------------------------------------------------------*/
PUBLIC LONG WINAPI Ctl3dDlgFramePaint(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
	{
	return Ctl3dDlgFramePaintI(hwnd, wm, wParam, lParam, TRUE);
	}

// Ctl3dDlgFramePaintI used only internally by Ctl3d
PRIVATE LONG WINAPI 
Ctl3dDlgFramePaintI(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, BOOL fDefWP)
	{
	LONG lResult;
	LONG lStyle;
	BOOL fBorder;

	WNDPROC defProc = fDefWP ? NULL : (WNDPROC) LpfnGetDefWndProc(hwnd, ctMax);

	if (defProc != NULL)
		lResult = CallWindowProc((FARPROC)defProc, hwnd, wm, wParam, lParam);
	else
		lResult = DefWindowProc(hwnd, wm, wParam, lParam);

	if (!g3d.f3dDialogs)
		return lResult;

	if ( IsIconic(hwnd) )
		return lResult;

	fBorder = CTL3D_BORDER;
	SendMessage(hwnd, WM_DLGBORDER, 0, (LPARAM)(int FAR *)&fBorder);
	lStyle = GetWindowLong(hwnd, GWL_STYLE);
	if (fBorder != CTL3D_NOBORDER && (lStyle & (WS_VISIBLE|WS_DLGFRAME|DS_MODALFRAME)) == (WS_VISIBLE|WS_DLGFRAME|DS_MODALFRAME))
		{
		BOOL fCaption;
		HBRUSH hbrSav;
		HDC hdc;
		RC rc;
		RC rcFill;
		int dyFrameTop;

		fCaption = (lStyle & WS_CAPTION) == WS_CAPTION;
		dyFrameTop = g3d.dyFrame - (fCaption ? dyBorder : 0);

		hdc = GetWindowDC(hwnd);
		GetWindowRect(hwnd, (LPRECT) &rc);
		rc.xRight = rc.xRight-rc.xLeft;
		rc.yBot = rc.yBot-rc.yTop;
		rc.xLeft = rc.yTop = 0;

		DrawRec3d(hdc, &rc, icvBtnShadow, icvWindowFrame, dr3All);
		InflateRect((LPRECT) &rc, -dxBorder, -dyBorder);
		DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnShadow, dr3All);
		InflateRect((LPRECT) &rc, -dxBorder, -dyBorder);
		
		hbrSav = SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnFace]);
		rcFill = rc;
		// Left
		rcFill.xRight = rcFill.xLeft+g3d.dxFrame;
		PatFill(hdc, &rcFill);
		// Right
		OffsetRect((LPRECT) &rcFill, rc.xRight-rc.xLeft-g3d.dxFrame, 0);
		PatFill(hdc, &rcFill);
		// Top
		rcFill.xLeft = rc.xLeft + g3d.dxFrame;
		rcFill.xRight = rc.xRight - g3d.dxFrame;
		rcFill.yBot = rcFill.yTop+dyFrameTop;
		PatFill(hdc, &rcFill);
		if (fCaption)
			{
			RC rcT;

			rcT = rcFill;
			rcT.yTop += dyFrameTop;
			rcT.yBot = rcT.yTop + g3d.dyCaption;
			DrawRec3d(hdc, &rcT, icvBtnShadow, icvBtnHilite, dr3All);
			}

		// Bottom
		rcFill.yTop += rc.yBot-rc.yTop-g3d.dxFrame;
		rcFill.yBot = rcFill.yTop + g3d.dyFrame;
		PatFill(hdc, &rcFill);
#ifdef CHISLEBORDER
		if (fBorder == CTL3D_CHISLEBORDER)
			{
			// This code doesn't work because it draws in the client area
			GetClientRect(hwnd, (LPRECT) &rc);
			OffsetRect((LPRECT) &rc, g3d.dxFrame+2*dxBorder, fCaption ? g3d.dyFrame+g3d.dyCaption : g3d.dyFrame+dyBorder);
			DrawRec3d(hdc, &rc, icvBtnShadow, icvBtnHilite, dr3Bot|dr3Left|dr3Right);
			rc.xLeft++;
			rc.xRight--;
			rc.yBot--;
			DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnShadow, dr3Bot|dr3Left|dr3Right);
			}
#endif
		SelectObject(hdc, hbrSav);
		ReleaseDC(hwnd, hdc);
		}
	return lResult;
	}


//begin DBCS: far east short cut key support
/*-----------------------------------------------------------------------
|	CTL3D Far East Support
-----------------------------------------------------------------------*/

/*-----------------------------------------------------------------------
|	Ctl3dWinIniChange
|	
|		App calls this when it gets a WM_WININICHANGE message
|		
|	Returns:
|		none
|		
-----------------------------------------------------------------------*/
PUBLIC VOID WINAPI Ctl3dWinIniChange(void)
	{
	TCHAR szShortCutMode[cchShortCutModeMax];
	CodeLpszDecl(szSectionWindows, TEXT("windows"));
	CodeLpszDecl(szEntryShortCutKK, TEXT("kanjimenu"));
	CodeLpszDecl(szEntryShortCutCH, TEXT("hangeulmenu"));
	CodeLpszDecl(szShortCutSbcsKK, TEXT("roman"));
	CodeLpszDecl(szShortCutSbcsCH, TEXT("english"));
	CodeLpszDecl(szShortCutDbcsKK, TEXT("kanji"));
	CodeLpszDecl(szShortCutDbcsCH, TEXT("hangeul"));

	if (!g3d.fDBCS)
		return;

	Win32Only(EnterCriticalSection(&g_CriticalSection));

	g3d.chShortCutPrefix = chShortCutSbcsPrefix;
	GetProfileString(szSectionWindows, szEntryShortCutKK, szShortCutSbcsKK, szShortCutMode, cchShortCutModeMax - 1);
	if (!lstrcmpi(szShortCutMode, szShortCutDbcsKK))
		g3d.chShortCutPrefix = chShortCutDbcsPrefix;
	GetProfileString(szSectionWindows, szEntryShortCutCH, szShortCutSbcsCH, szShortCutMode, cchShortCutModeMax - 1);
	if (!lstrcmpi(szShortCutMode, szShortCutDbcsCH))
		g3d.chShortCutPrefix = chShortCutDbcsPrefix;

	Win32Only(LeaveCriticalSection(&g_CriticalSection));
	}
//end DBCS



/*-----------------------------------------------------------------------
|   CTL3D Internal Routines
-----------------------------------------------------------------------*/


/*-----------------------------------------------------------------------
|   FInit3dDialogs
|
|	   Initialized 3d stuff
|
-----------------------------------------------------------------------*/
PRIVATE BOOL FAR FInit3dDialogs(VOID)
	{
	HDC hdc;
	WNDCLASS wc;

#ifdef DLL
#ifdef V2
	int nChars;
	LPTSTR pCh;
	static TCHAR MyDirectory[260];
	TCHAR OkDirectory[260];
#endif
#endif

	//if (g3d.verWindows >= ver40)
	//	  {
	//	  g3d.f3dDialogs = fFalse;
	//	  return fFalse;
	//	  }

	Win32Only(EnterCriticalSection(&g_CriticalSection));

#ifdef DLL
#ifdef V2

#ifdef WIN32
	{
		TCHAR szT[2];
		CodeLpszDecl(szSpecial, TEXT("Ctl3d_RunAlways"));
		if (GetEnvironmentVariable(szSpecial, szT, 2) != 0 && szT[0] == '1')
		{
			goto AllowBadInstall;
		}
	}
#endif

#ifdef WIN32
#ifdef UNICODE
	if (GetVersion() & 0x80000000)
	{
		Win16Or32(
			CodeLpszDeclA(lpszCtl3d, "CTL3DV2.DLL"),
			CodeLpszDeclA(lpszCtl3d, "CTL3D32.DLL"));
		CodeLpszDeclA(lpszBadInstMsg,
			"This application uses CTL3D32.DLL, which is not the correct version.  "
			"This version of CTL3D32.DLL is designed only for Windows NT systems.");
		MessageBoxA(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK);
		g3d.f3dDialogs = fFalse;
		goto Return;
	}
#else
	if (!(GetVersion() & 0x80000000))
	{
		Win16Or32(
			CodeLpszDeclA(lpszCtl3d, "CTL3DV2.DLL"),
			CodeLpszDeclA(lpszCtl3d, "CTL3D32.DLL"));
		CodeLpszDeclA(lpszBadInstMsg,
			"This application uses CTL3D32.DLL, which is not the correct version.  "
			"This version of CTL3D32.DLL is designed only for Win32s or Windows 95 systems.");
		MessageBoxA(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK);
		g3d.f3dDialogs = fFalse;
		goto Return;
	}
#endif
#endif
#ifndef SPECIAL_WOW_VERSION
	nChars = GetModuleFileName(g3d.hinstLib, MyDirectory, sizeof(MyDirectory)Win32Only(/sizeof(TCHAR)));
	for (pCh = (LPTSTR)(MyDirectory+nChars-1);
		 pCh >= (LPTSTR)MyDirectory;
		 pCh = Win32Or16(CharPrev(MyDirectory, pCh),AnsiPrev(MyDirectory, pCh)))
		{
		if (  *pCh == '\\' )
			{
			if ( *(pCh-1) != ':' )
				*pCh = 0;
			else
				*(pCh+1) = 0;
			break;
			}
		}

	nChars = GetSystemDirectory(OkDirectory, sizeof(OkDirectory)Win32Only(/sizeof(TCHAR)));
	if ( lstrcmpi(MyDirectory,OkDirectory ) )
		{
		nChars = GetWindowsDirectory(OkDirectory, sizeof(OkDirectory)Win32Only(/sizeof(TCHAR)));
		if ( lstrcmpi(MyDirectory,OkDirectory ) )
			{
			Win16Or32(
				CodeLpszDeclA(lpszCtl3d, "CTL3DV2.DLL"),
				CodeLpszDeclA(lpszCtl3d, "CTL3D32.DLL"));
			Win16Or32(
			CodeLpszDeclA(lpszBadInstMsg,
				"This application uses CTL3DV2.DLL, which has not been correctly installed.  "
				"CTL3DV2.DLL must be installed in the Windows system directory."),
			CodeLpszDeclA(lpszBadInstMsg,
				"This application uses CTL3D32.DLL, which has not been correctly installed.  "
				"CTL3D32.DLL must be installed in the Windows system directory."));
			Win32Only(LeaveCriticalSection(&g_CriticalSection));
			MessageBoxA(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK );
			g3d.f3dDialogs = fFalse;
			goto Return;
			}
		}
#endif //!SPECIAL_WOW_VERSION

Win32Only(AllowBadInstall:;)
#endif
#endif

	hdc = GetDC(NULL);
	g3d.f3dDialogs = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES) >= 4;
	// Win 3.1 EGA lies to us...
	if(GetSystemMetrics(SM_CYSCREEN) == 350 && GetSystemMetrics(SM_CXSCREEN) == 640)
	    g3d.f3dDialogs = fFalse;
	ReleaseDC(NULL, hdc);
	if (g3d.f3dDialogs)
		{
		int ct; 
		CodeLpszDecl(lpszC3dD, TEXT("C3dD"));
		
		CodeLpszDecl(lpszC3dOld, TEXT("C3d"));
		CodeLpszDecl(lpszC3dLOld, TEXT("C3dL"));
		CodeLpszDecl(lpszC3dHOld, TEXT("C3dH"));
		CodeLpszDecl(lpszC3d, TEXT("C3dNew"));
		CodeLpszDecl(lpszC3dL, TEXT("C3dLNew"));
		CodeLpszDecl(lpszC3dH, TEXT("C3dHNew"));

		g3d.aCtl3dOld = GlobalAddAtom(lpszC3dOld);
		if (g3d.aCtl3dOld == 0)
			{
			g3d.f3dDialogs = fFalse;
			goto Return;
			}
		g3d.aCtl3d	= GlobalAddAtom(lpszC3d);
		if (g3d.aCtl3d == 0)
			{
			g3d.f3dDialogs = fFalse;
			goto Return;
			}

		g3d.aCtl3dLowOld = GlobalAddAtom(lpszC3dLOld);
		g3d.aCtl3dHighOld = GlobalAddAtom(lpszC3dHOld);
		if (g3d.aCtl3dLowOld == 0 || g3d.aCtl3dHighOld == 0)
	  		{
			g3d.f3dDialogs = fFalse;
			return fFalse;
			}

		g3d.aCtl3dLow  = GlobalAddAtom(lpszC3dL);
		g3d.aCtl3dHigh = GlobalAddAtom(lpszC3dH);
		if (g3d.aCtl3dLow == 0 || g3d.aCtl3dHigh == 0)
	  		{
			g3d.f3dDialogs = fFalse;
			return fFalse;
			}

		g3d.aCtl3dDisable = GlobalAddAtom(lpszC3dD);
		if (g3d.aCtl3dDisable == 0)
			{
			g3d.f3dDialogs = fFalse;
			goto Return;
			}

		// DBCS
		g3d.fDBCS = GetSystemMetrics(SM_DBCSENABLED);
		Ctl3dWinIniChange();
                                                     
		if (InternalCtl3dColorChange(fTrue))        // load bitmap & brushes
			{
			for (ct = 0; ct < ctMax; ct++)
				{
				g3d.mpctctl[ct].lpfn = (FARPROC)mpctcdef[ct].lpfnWndProc;
				Assert(g3d.mpctctl[ct].lpfn != NULL);
                GetClassInfo(NULL, mpctcdef[ct].sz, (LPWNDCLASS) &wc);
				g3d.mpctctl[ct].lpfnDefProc = wc.lpfnWndProc;
				}
			if (GetClassInfo(NULL, WC_DIALOG, &wc))
				g3d.lpfnDefDlgWndProc = (FARPROC) wc.lpfnWndProc;
			else
				g3d.lpfnDefDlgWndProc = (FARPROC) DefDlgProc;
			}
		else
			{
			g3d.f3dDialogs = fFalse;
			}
		}
Return:
	Win32Only(LeaveCriticalSection(&g_CriticalSection));
	return g3d.f3dDialogs;
    }



/*-----------------------------------------------------------------------
|   End3dDialogs
|
|       Called at DLL termination to free 3d dialog stuff
-----------------------------------------------------------------------*/
PRIVATE VOID End3dDialogs(VOID)
	{
	int ct;

	Win32Only(EnterCriticalSection(&g_CriticalSection));

	for (ct = 0; ct < ctMax; ct++)
		{											   
		if(g3d.mpctctl[ct].lpfn != NULL)
			{
			FreeProcInstance(g3d.mpctctl[ct].lpfn);
			g3d.mpctctl[ct].lpfn = NULL;
			}
		}
	DeleteObjects();
	g3d.aCtl3dOld ? GlobalDeleteAtom(g3d.aCtl3dOld) : 0;
	g3d.aCtl3d ? GlobalDeleteAtom(g3d.aCtl3d) : 0;
	g3d.aCtl3dLowOld ? GlobalDeleteAtom(g3d.aCtl3dLowOld) : 0;
	g3d.aCtl3dHighOld ? GlobalDeleteAtom(g3d.aCtl3dHighOld) : 0;
	g3d.aCtl3dLow ? GlobalDeleteAtom(g3d.aCtl3dLow) : 0;
	g3d.aCtl3dHigh ? GlobalDeleteAtom(g3d.aCtl3dHigh) : 0;
	g3d.aCtl3dDisable ? GlobalDeleteAtom(g3d.aCtl3dDisable) : 0;

	g3d.f3dDialogs = fFalse;

	Win32Only(LeaveCriticalSection(&g_CriticalSection));

	}


PRIVATE BOOL InternalCtl3dColorChange(BOOL fForce)
	{
	ICV icv;
	CLRT clrtNew;
	HBITMAP hbmpCheckboxesNew;
	BRT brtNew;

	if (!g3d.f3dDialogs)
		return fFalse;

	for (icv = 0; icv < icvMax; icv++)
		clrtNew.rgcv[icv] = GetSysColor(mpicvSysColor[icv]);

	if (g3d.verWindows == ver30)
		clrtNew.rgcv[icvBtnHilite] = RGB(0xff, 0xff, 0xff);

	if (clrtNew.rgcv[icvGrayText] == 0L || clrtNew.rgcv[icvGrayText] == clrtNew.rgcv[icvBtnFace])
		{
		if (clrtNew.rgcv[icvBtnFace] == RGB(0x80, 0x80, 0x80))
			clrtNew.rgcv[icvGrayText] = RGB(0xc0, 0xc0, 0xc0);
		else
			clrtNew.rgcv[icvGrayText] = RGB(0x80, 0x80, 0x80);
		}

	if (fForce || MEMCMP(&g3d.clrt, &clrtNew, sizeof(CLRT)))
		{
		hbmpCheckboxesNew = LoadUIBitmap(g3d.hinstLib, MAKEINTRESOURCE(CTL3D_3DCHECK),
			clrtNew.rgcv[icvWindowText],
			clrtNew.rgcv[icvBtnFace],
			clrtNew.rgcv[icvBtnShadow],
			clrtNew.rgcv[icvBtnHilite],
			clrtNew.rgcv[icvWindow],
			clrtNew.rgcv[icvWindowFrame]);

		for (icv = 0; icv < icvBrushMax; icv++)
			brtNew.mpicvhbr[icv] = CreateSolidBrush(clrtNew.rgcv[icv]);

		for (icv = 0; icv < icvBrushMax; icv++)
			if (brtNew.mpicvhbr[icv] == NULL)
				goto OOM;

		if(hbmpCheckboxesNew != NULL)
			{
			DeleteObjects();
			g3d.brt = brtNew;
			g3d.clrt = clrtNew;
			g3d.hbmpCheckboxes = hbmpCheckboxesNew;
			return fTrue;
			}
		else
			{
OOM:
			for (icv = 0; icv < icvBrushMax; icv++)
				DeleteObjectNull(&brtNew.mpicvhbr[icv]);
			DeleteObjectNull(&hbmpCheckboxesNew);
			return fFalse;
			}
		}
	return fTrue;
	}


/*-----------------------------------------------------------------------
|   Ctl3dDlgProc
|   
|       Subclass DlgProc for use w/ Ctl3dAutoSubclass
|   
|   
|   Arguments:
|       HWND hwnd:  
|       int wm: 
|       WORD wParam:    
|       LPARAM lParam:  
|       
|   Returns:
|       
-----------------------------------------------------------------------*/
LRESULT __export _loadds WINAPI Ctl3dDlgProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
	{
	HBRUSH hbrush;
	FARPROC lpfnDlgProc;
	TCHAR szClass[cchClassMax];

	if ( wm == WM_NCDESTROY )
	return CleanupSubclass(hwnd, wm, wParam, lParam, ctMax);

	if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
	return CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd, wm, wParam, lParam);

	switch (wm)
		{
	case WM_CHECKSUBCLASS_OLD:
	case WM_CHECKSUBCLASS:
		*(int FAR *)lParam = fTrue;
		return ctMax+1000;

	case WM_INITDIALOG:
	  {
		long l;
		BOOL fSubclass;
		FARPROC lpfnWinProc;

		lpfnWinProc = LpfnGetDefWndProc(hwnd, ctMax);

		if (g3d.verWindows >= ver40 && (GetWindowLong(hwnd, GWL_STYLE) & 0x04))
			fSubclass = fFalse;
		else
			fSubclass = fTrue;
		SendMessage(hwnd, WM_DLGSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);

		if (!fSubclass)
			{
			Ctl3dUnsubclassCtl(hwnd);
			return CallWindowProc(lpfnWinProc, hwnd, wm, wParam, lParam);
			}

		l = CallWindowProc(lpfnWinProc, hwnd, wm, wParam, lParam);

		if (g3d.verWindows < ver40 || !(GetWindowLong(hwnd, GWL_STYLE) & 0x04))
			Ctl3dCheckSubclassDlg(hwnd, CTL3D_ALL);

		return l;
	  }

    case WM_NCPAINT:
	case WM_NCACTIVATE:
    case WM_SETTEXT:
		if (g3d.verWindows >= ver40 || IsIconic(hwnd) )
			return CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd, wm, wParam, lParam);
		else
			return Ctl3dDlgFramePaintI(hwnd, wm, wParam, lParam, FALSE);

#ifdef WIN32
	case WM_CTLCOLORSCROLLBAR:
	case WM_CTLCOLORBTN:
	case WM_CTLCOLORDLG:
	case WM_CTLCOLOREDIT:
	case WM_CTLCOLORLISTBOX:
	case WM_CTLCOLORMSGBOX:
	case WM_CTLCOLORSTATIC:
#else
	case WM_CTLCOLOR:
#endif
	// Is this really a dialog
	GetClassName(hwnd, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));
	if (lstrcmp(TEXT("#32770"),szClass) != 0 )
	   {
#ifdef WIN32
		  hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
						   wm-WM_CTLCOLORMSGBOX+CTLMSGOFFSET, wParam, lParam);
#else
		  hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
						   CTL3D_CTLCOLOR, wParam, lParam);
#endif
		  if (hbrush == (HBRUSH) fFalse || hbrush == (HBRUSH)1)
			hbrush = Ctl3dCtlColorEx(wm, wParam, lParam);
	   }
	else
	 {
		lpfnDlgProc = (FARPROC) GetWindowLong(hwnd, DWL_DLGPROC);

		if (lpfnDlgProc == NULL )
			{
			hbrush = Ctl3dCtlColorEx(wm, wParam, lParam);
			}
		else
			{
#ifdef WIN32
			if ( (LONG)lpfnDlgProc > 0xFFFF0000 && g3d.verWindows <= ver31)
				{
				// We have a Uni-code / non Unicode issue.
				// If this is before Daytona, then I CAN NOT call because it may be NULL, but
				// the returned value is not-null. NT Bug.
				// So Just send our own message to the window proc instead
				hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
												wm-WM_CTLCOLORMSGBOX+CTLMSGOFFSET, wParam, lParam);
				if (hbrush == (HBRUSH) fFalse || hbrush == (HBRUSH)1)
					hbrush = Ctl3dCtlColorEx(wm, wParam, lParam);
				}
			else
				{
#endif
				hbrush = (HBRUSH) CallWindowProc(lpfnDlgProc, hwnd, wm, wParam, lParam);
				if (hbrush == (HBRUSH) fFalse || hbrush == (HBRUSH)1)
					{
#ifdef WIN32
					hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
												wm-WM_CTLCOLORMSGBOX+CTLMSGOFFSET, wParam, lParam);
#else
					hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
												CTL3D_CTLCOLOR, wParam, lParam);
#endif
					if (hbrush == (HBRUSH) fFalse || hbrush == (HBRUSH)1)
						hbrush = Ctl3dCtlColorEx(wm, wParam, lParam);
					}
				}
#ifdef WIN32
			}
#endif
	}
		if (hbrush != (HBRUSH) fFalse)
			return  (LRESULT)hbrush;
		break;
		}						  
	return CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd, wm, wParam, lParam);
	}

PRIVATE BOOL NEAR DoesChildNeedSubclass(HWND hwnd)
	{
		if (!LpfnGetDefWndProcNull(hwnd))
			return fFalse;
		if (g3d.verWindows >= ver40 && GetWindowLong(hwnd, GWL_STYLE) & 0x04)
			return fFalse;
		return fTrue;
	}

/*-----------------------------------------------------------------------
|   Ctl3dHook
|   
|	   CBT Hook to watch for window creation.  Automatically subclasses all
|   dialogs w/ Ctl3dDlgProc
|   
|   Arguments:
|	   int code:   
|	   WORD wParam:	
|	   LPARAM lParam:  
|	   
|   Returns:
|	   
-----------------------------------------------------------------------*/
LRESULT __export _loadds WINAPI Ctl3dHook(int code, WPARAM wParam, LPARAM lParam)
	{
	int iclihk;
	HANDLE htask;

	htask = Win32Or16((HANDLE)GetCurrentThreadId(), GetCurrentTask());
	Win32Only(EnterCriticalSection(&g_CriticalSection));
	if (htask != g3d.htaskCache)
		{
		for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
			{
			if (g3d.rgclihk[iclihk].htask == htask)
				{
				g3d.iclihkCache = iclihk;
				g3d.htaskCache = htask;
				break;
				}
		}
		if ( iclihk == g3d.iclihkMac )
			{
			// didn't find task in hook table.  This could be bad, but
			// returning 0L is about all we can doo.
			//
			// Actually not. The hhook isn't used anyway just set it to NULL.
			// and call the next hook..... KGM
			Win32Only(LeaveCriticalSection(&g_CriticalSection));
			return CallNextHookEx((HHOOK)0L, code, wParam, lParam);
			}
		}
	iclihk = g3d.iclihkCache;
	Win32Only(LeaveCriticalSection(&g_CriticalSection));

	if (code == HCBT_CREATEWND)
		{
		LPCREATESTRUCT lpcs;
		lpcs = ((LPCBT_CREATEWND)lParam)->lpcs;

		  if (lpcs->lpszClass == WC_DIALOG)
			{
			if (g3d.verBase == 32)
			   {
				BOOL fSubclass;
				if (g3d.verWindows >= ver40 && (GetWindowLong((HWND)wParam, GWL_STYLE) & 0x04))
					fSubclass = fFalse;
				else
					fSubclass = fTrue;
				SendMessage((HWND)wParam, WM_DLGSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);
				if (fSubclass)
			   		SubclassWindow((HWND)wParam, (FARPROC) Ctl3dDlgProc);
			   }
			else
			   {
			   HookSubclassWindow((HWND)wParam, (FARPROC) Ctl3dDlgProc);
			   }
			goto Zing;
			}
		  if (!(g3d.rgclihk[iclihk].dwFlags & CTL3D_SUBCLASS_DYNCREATE))
			goto Zing;

		  if (DoesChildNeedSubclass(lpcs->hwndParent) ||
			 (lpcs->hwndParent && g3d.verBase != 24 &&
				DoesChildNeedSubclass(GetParent(lpcs->hwndParent))))
			{
			DoSubclassCtl((HWND)wParam, CTL3D_ALL, INCBTHOOK, lpcs->hwndParent);
			}
		}

Zing:;
	Win32Only(return CallNextHookEx(g3d.rgclihk[iclihk].hhook, code, wParam, lParam));
#ifdef DLL
	Win16Only(return (*g3d.lpfnCallNextHookEx)(g3d.rgclihk[iclihk].hhook, code, wParam, lParam));
#else
	Win16Only(return (CallNextHookEx(g3d.rgclihk[iclihk].hhook, code, wParam, lParam)));
#endif
	}




/*-----------------------------------------------------------------------
|   CTL3D F* routines
|   
|   These routines determine whether or not the given control may be
|	   subclassed.  They may recursively call DoSubclassCtl in the
|	   case of multi-control controls
|
|   Returns:
|	   fTrue if can subclass the given control.
-----------------------------------------------------------------------*/


PRIVATE BOOL FBtn(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
	{
	if (g3d.verWindows >= ver40)
	   {
		return fFalse;
	   }
    style &= ~(BS_LEFTTEXT);
	return ( LOWORD(style) >= BS_PUSHBUTTON && LOWORD(style) <= BS_AUTORADIOBUTTON);
	}

PRIVATE BOOL FEdit(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
	{
	if (g3d.verWindows >= ver40 && hwndParent)
		{
		 TCHAR szClass[cchClassMax];
		 GetClassName(hwndParent, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));
		 if (lstrcmp(szClass, mpctcdef[ctCombo].sz) == 0 )
			return fFalse;
		 else
			return fTrue;
		}
	else
	return fTrue;
	}

PRIVATE BOOL FList(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
	{
	if (g3d.verWindows >= ver40 && hwndParent)
		{
		 TCHAR szClass[cchClassMax];
		 GetClassName(hwndParent, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));
		 if (lstrcmp(szClass, mpctcdef[ctCombo].sz) == 0 )
			return fFalse;
		 else
			return fTrue;
		}
	else
	   return fTrue;
	}

PRIVATE BOOL FComboList(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
	{

	if (g3d.verWindows >= ver40)
	   return fFalse;

	if ( wCallFlags == INCBTHOOK )
		{
		LONG style;
		style = GetWindowLong(hwndParent, GWL_STYLE);
		if (!(((style & 0x0003) == CBS_DROPDOWN) || ((style & 0x0003) == CBS_DROPDOWNLIST)))
			return fTrue;
		else
			return fFalse;
		}

	return fTrue;
	}

PRIVATE BOOL FCombo(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
	{
	HWND hwndEdit;
	HWND hwndList;

	if (g3d.verWindows >= ver40)
	   return fFalse;

	if ((style & 0x0003) == CBS_DROPDOWN)
		{
		if ( wCallFlags == INCBTHOOK )
			{
			return fFalse;
			}
		// Subclass edit so bottom border of the edit draws properly...This case
		// is specially handled in ListEditPaint3d
		hwndEdit = GetWindow(hwnd, GW_CHILD);
		if (hwndEdit != NULL)
			DoSubclassCtl(hwndEdit, CTL3D_EDITS, wCallFlags, hwnd);
		return fTrue;
		}
	else if ((style & 0x0003) == CBS_DROPDOWNLIST )
		{
		return fTrue;
		}
	else // assume simple // if ((style & 0x0003) == CBS_SIMPLE)
		{
		if ( wCallFlags == INCBTHOOK )
			{
				return fTrue;
			}
		hwndList = GetWindow(hwnd, GW_CHILD);
		if (hwndList != NULL)
			{
			// Subclass list & edit box so they draw properly.  We also
			// subclass the combo so we can hide/show/move it and the
			// 3d effects outside the client area get erased
			DoSubclassCtl(hwndList, CTL3D_LISTBOXES, wCallFlags, hwnd);

			hwndEdit = GetWindow(hwndList, GW_HWNDNEXT);
			if (hwndEdit != NULL)
				DoSubclassCtl(hwndEdit, CTL3D_EDITS, wCallFlags, hwnd);
			return fTrue;
			}
		return fFalse;  
		}
	}

PRIVATE BOOL FStatic(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
	{
	int wStyle;

	wStyle = LOWORD(style) & 0x1f;
	return (wStyle != SS_ICON &&
		((grbit & CTL3D_STATICTEXTS) && 
		(wStyle <= SS_RIGHT || wStyle == SS_LEFTNOWORDWRAP) ||
		((grbit & CTL3D_STATICFRAMES) &&
		((wStyle >= SS_BLACKRECT && wStyle <= SS_WHITEFRAME) ||
		 (g3d.verWindows < ver40 && wStyle >= 0x10 && wStyle <= 0x12)))));
	}



/*-----------------------------------------------------------------------
|   DoSubclassCtl
|   
|	   Actually subclass the control
|   
|   
|   Arguments:
|	   HWND hwnd:  
|	   WORD grbit: 
|	   WORD wCallFlags
|   Returns:
|	   
-----------------------------------------------------------------------*/
PRIVATE BOOL DoSubclassCtl(HWND hwnd, WORD grbit, WORD wCallFlags, HWND hwndParent)
	{
	LONG style;
	int ct;
	BOOL fCan;
	TCHAR szClass[cchClassMax];

	// Is this already subclassed by CTL3D?
	if (LpfnGetDefWndProcNull(hwnd) != (FARPROC) NULL)
	   return fFalse;

	GetClassName(hwnd, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));

	for (ct = 0; ct < ctMax; ct++)
		{
		if ((mpctcdef[ct].msk & grbit) &&
			(lstrcmp(mpctcdef[ct].sz,szClass) == 0))
			{
			style = GetWindowLong(hwnd, GWL_STYLE);
			fCan = mpctcdef[ct].lpfnFCanSubclass(hwnd, style, grbit, wCallFlags, hwndParent);
			if (fCan == fTrue)
				{
				if ( wCallFlags == INCBTHOOK && g3d.verBase == 16 )
					HookSubclassWindow(hwnd, g3d.mpctctl[ct].lpfn);
				else
					SubclassWindow(hwnd, g3d.mpctctl[ct].lpfn);
				}
			return fCan != fFalse;
			}
		}

	return fFalse;
	}



/*-----------------------------------------------------------------------
|   Inval3dCtl
|   
|	   Invalidate the controls rect in response to a WM_SHOWWINDOW or
|   WM_WINDOWPOSCHANGING message.  This is necessary because ctl3d draws
|   the 3d effects of listboxes, combos & edits outside the controls client
|   rect.
|   
|   Arguments:
|	   HWND hwnd:  
|	   WINDOWPOS FAR *lpwp:	
|	   
|   Returns:
|	   
-----------------------------------------------------------------------*/
PRIVATE VOID Inval3dCtl(HWND hwnd, WINDOWPOS FAR *lpwp)
	{
	RC rc;
	HWND hwndParent;
	LONG lStyle;
	unsigned flags;

	GetWindowRect(hwnd, (LPRECT) &rc);
	lStyle = GetWindowLong(hwnd, GWL_STYLE);
	if (lStyle & WS_VISIBLE)
		{
		if (lpwp != NULL)
			{
			flags = lpwp->flags;

			//
			// Is all this necessary ? Are we moving or sizing ?
			//
			if ( !((flags & SWP_HIDEWINDOW) || (flags & SWP_SHOWWINDOW)) &&
				(flags & SWP_NOMOVE) && (flags & SWP_NOSIZE) )
			   // Nope
			   return;

			// handle integral height listboxes (or any other control which
			// shrinks from the bottom)
			if ((flags & (SWP_NOMOVE|SWP_NOSIZE)) == SWP_NOMOVE &&
				(lpwp->cx == (rc.xRight-rc.xLeft) && lpwp->cy <= (rc.yBot-rc.yTop)))
				rc.yTop = rc.yTop+lpwp->cy+1;	   // +1 to offset InflateRect
			}
		InflateRect((LPRECT) &rc, 1, 1);
		hwndParent = GetParent(hwnd);
		ScreenToClient(hwndParent, (LPPOINT) &rc);
		ScreenToClient(hwndParent, ((LPPOINT) &rc)+1);
		if(lStyle & WS_VSCROLL)
			rc.xRight ++;
		InvalidateRect(hwndParent, (LPRECT) &rc, fFalse);
		}
	}

/*-----------------------------------------------------------------------
|	Val3dCtl
|	   
-----------------------------------------------------------------------*/
PRIVATE VOID Val3dCtl(HWND hwnd)
	{
	RC rc;
	HWND hwndParent;
	LONG lStyle;

	lStyle = GetWindowLong(hwnd, GWL_STYLE);
	GetWindowRect(hwnd, (LPRECT) &rc);
	InflateRect((LPRECT) &rc, 1, 1);
	hwndParent = GetParent(hwnd);
	ScreenToClient(hwndParent, (LPPOINT) &rc);
	ScreenToClient(hwndParent, ((LPPOINT) &rc)+1);
	if(lStyle & WS_VSCROLL)
		rc.xRight ++;
	ValidateRect(hwndParent, (LPRECT) &rc);
	}

/*-----------------------------------------------------------------------
|   CTL3D Subclass Wndprocs
-----------------------------------------------------------------------*/

/* These values are assumed for bit shifting operations */
#define BFCHECK	 0x0003
#define BFSTATE	 0x0004
#define BFFOCUS	 0x0008
#define BFINCLICK   0x0010  /* Inside click code */
#define BFCAPTURED  0x0020  /* We have mouse capture */
#define BFMOUSE	 0x0040  /* Mouse-initiated */
#define BFDONTCLICK 0x0080  /* Don't check on get focus */

#define bpText  0x0002
#define bpCheck 0x0004
#define bpFocus 0x0008  // must be same as BFFOCUS
#define bpBkgnd 0x0010
#define bpEraseGroupText 0x0020

PRIVATE VOID DrawPushButton(HWND hwnd, HDC hdc, RC FAR *lprc, LPTSTR lpch, int cch, WORD bs, BOOL fDown)
	{
	// int dxyBrdr;
	int dxyShadow;
	HBRUSH hbrSav;
	RC rcInside;
	rcInside = *lprc;

//	if (!(grbitStyle & bitFCoolButtons))
		{
		DrawRec3d(hdc, lprc, icvWindowFrame, icvWindowFrame, dr3All);
		InflateRect((LPRECT) &rcInside, -1, -1);
		if (bs == LOWORD(BS_DEFPUSHBUTTON) && IsWindowEnabled(hwnd))
			{
			// dxyBrdr = 2;
			DrawRec3d(hdc, &rcInside, icvWindowFrame, icvWindowFrame, dr3All);
			InflateRect((LPRECT) &rcInside, -1, -1);
			}
		// else
			// dxyBrdr = 1;

		// Notch the corners
		PatBlt(hdc, lprc->xLeft, lprc->yTop, dxBorder, dyBorder, PATCOPY);
		/* Top xRight corner */
		PatBlt(hdc, lprc->xRight - dxBorder, lprc->yTop, dxBorder, dyBorder, PATCOPY);
		/* yBot xLeft corner */
		PatBlt(hdc, lprc->xLeft, lprc->yBot - dyBorder, dxBorder, dyBorder, PATCOPY);
		/* yBot xRight corner */
		PatBlt(hdc, lprc->xRight - dxBorder, lprc->yBot - dyBorder, dxBorder, dyBorder, PATCOPY);
		dxyShadow = 1 + !fDown;
		}
//	else
//		dxyShadow = 1;

	// draw upper left hilite/shadow

	if (fDown)
		hbrSav = SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnShadow]);
	else
		hbrSav = SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnHilite]);

	PatBlt(hdc, rcInside.xLeft, rcInside.yTop, dxyShadow,
		(rcInside.yBot - rcInside.yTop), PATCOPY);
	PatBlt(hdc, rcInside.xLeft, rcInside.yTop,
		(rcInside.xRight - rcInside.xLeft), dxyShadow, PATCOPY);

	// draw lower right shadow (only if not down)
	if (!fDown) // || (grbitStyle & bitFCoolButtons))
		{
		int i;

		if (fDown)
			SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnHilite]);
		else
			SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnShadow]);

		rcInside.yBot--;
		rcInside.xRight--;

		for (i = 0; i < dxyShadow; i++)
			{
		 PatBlt(hdc, rcInside.xLeft, rcInside.yBot,
				rcInside.xRight - rcInside.xLeft + dxBorder, dyBorder, 
				PATCOPY);
			PatBlt(hdc, rcInside.xRight, rcInside.yTop, dxBorder,
				rcInside.yBot - rcInside.yTop, PATCOPY);
			if (i < dxyShadow-1)
				InflateRect((LPRECT) &rcInside, -dxBorder, -dyBorder);
			}
		}
	// draw the button face

	rcInside.xLeft++;
	rcInside.yTop++;

	SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnFace]);
	PatBlt(hdc, rcInside.xLeft, rcInside.yTop, rcInside.xRight-rcInside.xLeft,
		rcInside.yBot - rcInside.yTop, PATCOPY);

	// Draw the durned text

	if(!IsWindowEnabled(hwnd))
		SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);
	
	{
	int dy;
	int dx;

	MyGetTextExtent(hdc, lpch, &dx, &dy);
	rcInside.yTop += (rcInside.yBot-rcInside.yTop-dy)/2;
	rcInside.xLeft += (rcInside.xRight-rcInside.xLeft-dx)/2;
	rcInside.yBot = min(rcInside.yTop+dy, rcInside.yBot);
	rcInside.xRight = min(rcInside.xLeft+dx, rcInside.xRight);
	}

	if (fDown)
		{
		OffsetRect((LPRECT) &rcInside, 1, 1);
		rcInside.xRight = min(rcInside.xRight, lprc->xRight-3);
		rcInside.yBot = min(rcInside.yBot, lprc->yBot-3);
		}

	DrawText(hdc, lpch, cch, (LPRECT) &rcInside, DT_LEFT|DT_SINGLELINE);
	
	if (hwnd == GetFocus())
		{
		InflateRect((LPRECT) &rcInside, 1, 1);
		IntersectRect((LPRECT) &rcInside, (LPRECT) &rcInside, (LPRECT) lprc);
		DrawFocusRect(hdc, (LPRECT) &rcInside);
		}

	if (hbrSav)
		SelectObject(hdc, hbrSav);
	}


/*-----------------------------------------------------------------------
|   BtnPaint
|   
|	   Paint a button
|   
|   Arguments:
|	   HWND hwnd:  
|	   HDC hdc:	
|	   int bp: 
|	   
|   Returns:
|	   
-----------------------------------------------------------------------*/
PRIVATE VOID BtnPaint(HWND hwnd, HDC hdc, int bp)
	{
	RC rc;
	RC rcClient;
	HFONT hfont;
	int bs;
	int bf;
	HBRUSH hbrBtn;
	HWND hwndParent;
	int xBtnBmp;
	int yBtnBmp;
	HBITMAP hbmpSav;
	HDC hdcMem;
	TCHAR szTitle[256];
	int cch;
	BOOL fEnabled;
    BOOL fLeftText;

	bs = (int) GetWindowLong(hwnd, GWL_STYLE);
    fLeftText = (bs & Win32Or16(0x00000020, 0x0020));
	bs &= Win32Or16(0x0000001F, 0x001F);
	hwndParent = GetParent(hwnd);
	SetBkMode(hdc, OPAQUE);
	GetClientRect(hwnd, (LPRECT)&rcClient);
	rc = rcClient;
	if((hfont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L)) != NULL)
		hfont = SelectObject(hdc, hfont);

	SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
	SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
	hbrBtn = SEND_COLOR_BUTTON_MESSAGE(hwndParent, hwnd, hdc);
	hbrBtn = SelectObject(hdc, hbrBtn);
	IntersectClipRect(hdc, rc.xLeft, rc.yTop, rc.xRight, rc.yBot);
	if(bp & bpBkgnd && (bs != BS_GROUPBOX))
		PatBlt(hdc, rc.xLeft, rc.yTop, rc.xRight-rc.xLeft, rc.yBot-rc.yTop, PATCOPY);

	fEnabled = IsWindowEnabled(hwnd);
	bf = (int) SendMessage(hwnd, BM_GETSTATE, 0, 0L);
	yBtnBmp = 0;
	xBtnBmp = (((bf&BFCHECK) != 0) | ((bf&BFSTATE) >> 1)) * 14;
	if (!fEnabled)
		xBtnBmp += 14*(2+((bf&BFCHECK) != 0));
	if(bp & (bpText|bpFocus) || 
			bs == BS_PUSHBUTTON || bs == BS_DEFPUSHBUTTON)
		cch = GetWindowText(hwnd, szTitle, sizeof(szTitle)Win32Only(/sizeof(TCHAR)));
	switch(bs)
		{
#ifdef DEBUG
		default:
			Assert(fFalse);
			break;
#endif
		case BS_PUSHBUTTON:
		case BS_DEFPUSHBUTTON:
			DrawPushButton(hwnd, hdc, &rcClient, szTitle, cch, LOWORD(bs), bf & BFSTATE);
			break;

		case BS_RADIOBUTTON:
		case BS_AUTORADIOBUTTON:
			yBtnBmp = 13;
			goto DrawBtn;
		case BS_3STATE:
		case BS_AUTO3STATE:
			Assert((BFSTATE >> 1) == 2);
			if((bf & BFCHECK) == 2)
				yBtnBmp = 26;
			// fall through
		case BS_CHECKBOX:
		case BS_AUTOCHECKBOX:
DrawBtn:
			if(bp & bpCheck)
				{
				hdcMem = CreateCompatibleDC(hdc);
				if(hdcMem != NULL)
					{
					hbmpSav = SelectObject(hdcMem, g3d.hbmpCheckboxes);
					if(hbmpSav != NULL)
						{
                        if (fLeftText)
						    BitBlt(hdc, rc.xRight - 14, rc.yTop+(rc.yBot-rc.yTop-13)/2,
						    	14, 13, hdcMem, xBtnBmp, yBtnBmp, SRCCOPY);
                        else
						    BitBlt(hdc, rc.xLeft, rc.yTop+(rc.yBot-rc.yTop-13)/2,
						    	14, 13, hdcMem, xBtnBmp, yBtnBmp, SRCCOPY);
				    	SelectObject(hdcMem, hbmpSav);
						}
					DeleteDC(hdcMem);
					}
				}
			if(bp & bpText)
				{
				// BUG! this assumes we have only 1 hbm3dCheck type
                if (fLeftText)
                    rc.xRight = rcClient.xRight - (14+4);
                else
				    rc.xLeft = rcClient.xLeft + 14+4;
				if(!fEnabled)
					SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);
				DrawText(hdc, szTitle, cch, (LPRECT) &rc, DT_VCENTER|DT_LEFT|DT_SINGLELINE);
				}
			if(bp & bpFocus)
				{
				int dx;
				int dy;

				MyGetTextExtent(hdc, szTitle, &dx, &dy);
				rc.yTop = (rc.yBot-rc.yTop-dy)/2;
				rc.yBot = rc.yTop+dy;
				rc.xLeft = rcClient.xLeft;
				if (fLeftText)
                {
				    rc.xLeft = rcClient.xLeft;
                    rcClient.xRight -= (14+4);
                }
                else
    				rc.xLeft = rcClient.xLeft + (14+4);
				rc.xRight = rc.xLeft + dx;
				InflateRect((LPRECT) &rc, 1, 1);
				IntersectRect((LPRECT) &rc, (LPRECT) &rc, (LPRECT) &rcClient);
				DrawFocusRect(hdc, (LPRECT) &rc);
				}
			break;
		case BS_GROUPBOX:
			if(bp & (bpText|bpCheck))
				{
				int dy;
				int dx;

				MyGetTextExtent(hdc, szTitle, &dx, &dy);
				if (dy == 0)
					{
					int dxT;
					MyGetTextExtent(hdc, TEXT("X"), &dxT, &dy);
					}
					
				rc.xLeft += 4;
				rc.xRight = rc.xLeft + dx + 4;
				rc.yBot = rc.yTop + dy;

				if (bp & bpEraseGroupText)
					{
					RC rcT;

					rcT = rc;
					rcT.xRight = rcClient.xRight;
					// Hack!
					ClientToScreen(hwnd, (LPPOINT) &rcT);
					ClientToScreen(hwnd, ((LPPOINT) &rcT)+1);
					ScreenToClient(hwndParent, (LPPOINT) &rcT);
					ScreenToClient(hwndParent, ((LPPOINT) &rcT)+1);
					InvalidateRect(hwndParent, (LPRECT) &rcT, fTrue);
					return;
					}

				rcClient.yTop += dy/2;
				rcClient.xRight--;
				rcClient.yBot--;
				DrawRec3d(hdc, &rcClient, icvBtnShadow, icvBtnShadow, dr3All);
				OffsetRect((LPRECT) &rcClient, 1, 1);
				DrawRec3d(hdc, &rcClient, icvBtnHilite, icvBtnHilite, dr3All);

				if(!fEnabled)
					SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);
				DrawText(hdc, szTitle, cch, (LPRECT) &rc, DT_LEFT|DT_SINGLELINE);
				}
			break;
		}

	SelectObject(hdc, hbrBtn);
	if(hfont != NULL)
		SelectObject(hdc, hfont);
	}

LRESULT __export _loadds WINAPI BtnWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
	{
	LONG lRet;
	LONG lStyle;
	PAINTSTRUCT ps;
	HDC hdc;
	int bf;
	int bfNew;
	int bp;

	if ( wm == WM_NCDESTROY )
	return CleanupSubclass(hwnd, wm, wParam, lParam, ctButton);

	if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
	return CallWindowProc(LpfnGetDefWndProc(hwnd, ctButton), hwnd, wm, wParam, lParam);

	switch(wm)
		{
	case WM_CHECKSUBCLASS_OLD:
	case WM_CHECKSUBCLASS:
		*(int FAR *)lParam = fTrue;
		return ctButton+1000;

	case WM_SETTEXT:
		lStyle = GetWindowLong(hwnd, GWL_STYLE);
		if ((lStyle & WS_VISIBLE) && (LOWORD(lStyle) & 0x1f) == BS_GROUPBOX)
			{
			// total hack -- if group box text length shortens then
			// we have to erase the old text.  BtnPaint will Invalidate
			// the rect of the text so everything will redraw.
			bp = bpText | bpEraseGroupText;
			}
		else
			{
			bp = bpText|bpCheck|bpBkgnd;
			}
		goto DoIt;

	case BM_SETSTATE:
	case BM_SETCHECK:
		bp = bpCheck;
		goto DoIt;
	case WM_KILLFOCUS:
		// HACK! Windows will go into an infinite loop trying to sync the
		// states of the AUTO_RADIOBUTTON in this group.  (we turn off the
		// visible bit so it gets skipped in the enumeration)
		// Disable this code by clearing the STATE bit
		if ((LOWORD(GetWindowLong(hwnd, GWL_STYLE)) & 0x1F) == BS_AUTORADIOBUTTON)
			SendMessage(hwnd, BM_SETSTATE, 0, 0L);
		bp = 0;
		goto DoIt;
	case WM_ENABLE:
		bp = bpCheck | bpText;
		goto DoIt;
	case WM_SETFOCUS:
		// HACK! if wParam == NULL we may be activated via the task manager
		// Erase background of control because a WM_ERASEBKGND messsage has not
		// arrived yet for the dialog
		// bp = wParam == (WPARAM)NULL ? (bpCheck | bpText | bpBkgnd) : (bpCheck | bpText);
		bp = bpCheck | bpText | bpBkgnd;
DoIt:
        bf = (int) SendMessage(hwnd, BM_GETSTATE, 0, 0L);
        if((lStyle = GetWindowLong(hwnd, GWL_STYLE)) & WS_VISIBLE)
			{
			if ( wm != WM_SETFOCUS )
			   SetWindowLong(hwnd, GWL_STYLE, lStyle & ~(WS_VISIBLE));
            lRet = CallWindowProc(LpfnGetDefWndProc(hwnd, ctButton), hwnd, wm, wParam, lParam);

			if ( wm != WM_SETFOCUS )
			   SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE)|WS_VISIBLE);
			bfNew = (int) SendMessage(hwnd, BM_GETSTATE, 0, 0L);
			if((wm != BM_SETSTATE && wm != BM_SETCHECK) ||
				bf != bfNew)
				{
				hdc = GetDC(hwnd);
				if (hdc != NULL)
					{
					Assert(BFFOCUS == bpFocus);
					/* If the check state changed, redraw no matter what,
						because it won't have during the above call to the def
						wnd proc */
					if ((bf & BFCHECK) != (bfNew & BFCHECK))
						bp |= bpCheck;
					ExcludeUpdateRgn(hdc, hwnd);
					BtnPaint(hwnd, hdc, bp|((bf^bfNew)&BFFOCUS));
					ReleaseDC(hwnd, hdc);
					}
				}
			return lRet;
			}
		break;
	case WM_PAINT:
		bf = (int) SendMessage(hwnd, BM_GETSTATE, 0, 0L);
		if ((hdc = (HDC) wParam) == NULL)
			hdc = BeginPaint(hwnd, &ps);
		if(GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE)
			BtnPaint(hwnd, hdc, bpText|bpCheck|(bf&BFFOCUS));
		if (wParam == (WPARAM)NULL)
			EndPaint(hwnd, &ps);
		return 0L;
		}
    return CallWindowProc(LpfnGetDefWndProc(hwnd, ctButton), hwnd, wm, wParam, lParam);
	}


void ListEditPaint3d(HWND hwnd, BOOL fEdit, int ct)
	{
	CTLID id;
	RC rc;
	HDC hdc;
	HWND hwndParent;
	LONG lStyle;
	DR3 dr3;

	if(!((lStyle = GetWindowLong(hwnd, GWL_STYLE)) & WS_VISIBLE))
		return;

	if ((ct == ctCombo && (lStyle & 0x003) == CBS_DROPDOWNLIST))
		{
		if ( SendMessage(hwnd, CB_GETDROPPEDSTATE,0,0L) )
			return;
		}

	if (fEdit)
		HideCaret(hwnd);

	GetWindowRect(hwnd, (LPRECT) &rc);		  

	ScreenToClient(hwndParent = GetParent(hwnd), (LPPOINT) &rc);
	ScreenToClient(hwndParent, ((LPPOINT) &rc)+1);

	hdc = GetDC(hwndParent);

	dr3 = dr3All;

	if(lStyle & WS_HSCROLL)
		dr3 = dr3 & ~dr3Bot;

	if(lStyle & WS_VSCROLL)
		dr3 = dr3 & ~dr3Right;

	// don't draw the top if it's a listbox of a simple combo
	id = GetControlId(hwnd);
	if (id == (CTLID) (1000 + fEdit))
		{
		TCHAR szClass[cchClassMax];
		BOOL fSubclass = 666;
		int ctParent;

		// could be superclassed!
		fSubclass = 666;
		ctParent = (int)SendMessage(hwndParent, WM_CHECKSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);
		if (fSubclass == 666)
			ctParent = (int)SendMessage(hwndParent, WM_CHECKSUBCLASS_OLD, 0, (LPARAM)(int FAR *)&fSubclass);


		// could be subclassed!
		GetClassName(hwndParent, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));
		if (lstrcmp(szClass, mpctcdef[ctCombo].sz) == 0 ||
			(fSubclass == fTrue && ctParent == ctCombo+1000))
			{
			HWND hwndComboParent;

			hwndComboParent = GetParent(hwndParent);

			Win16Only(GetWindowRect(hwnd, (LPRECT) &rc));
			Win16Only(ScreenToClient(hwndComboParent, (LPPOINT) &rc));
			Win16Only(ScreenToClient(hwndComboParent, ((LPPOINT) &rc)+1));

			Win32Only(MapWindowPoints(hwndParent, hwndComboParent, (POINT*)&rc, 2));

			ReleaseDC(hwndParent, hdc);
			hdc = GetDC(hwndComboParent);

			if (fEdit)
				{
				RC rcList;
				HWND hwndList;
				long style;

				style = GetWindowLong(hwndParent, GWL_STYLE);
				if (!(((style & 0x0003) == CBS_DROPDOWN)
				   || ((style & 0x0003) == CBS_DROPDOWNLIST)))
					{
					dr3 &= ~dr3Bot;
			
					hwndList = GetWindow(hwndParent, GW_CHILD);
					GetWindowRect(hwndList, (LPRECT) &rcList);		  
			
					
					rc.xRight -= rcList.xRight-rcList.xLeft;
					DrawInsetRect3d(hdc, &rc, dr3Bot|dr3HackBotRight);
					rc.xRight += rcList.xRight-rcList.xLeft;		
					}
				else
					{
					//
					// Is the drop down on the parent down ? if so don't paint.
					//
					if ( SendMessage(hwndParent, CB_GETDROPPEDSTATE,0,0L) )
						{
						ReleaseDC(hwndComboParent, hdc);
						ShowCaret(hwnd);
						return;
						}
					}
				}
			else
				{
				rc.yTop++;
				dr3 &= ~dr3Top;
				}

			hwndParent = hwndComboParent;

			}
		}

	DrawInsetRect3d(hdc, &rc, dr3);

	if ((ct == ctCombo && (lStyle & 0x003) == CBS_DROPDOWNLIST))
		{
		rc.xLeft = rc.xRight - GetSystemMetrics(SM_CXVSCROLL);
		DrawRec3d(hdc, &rc, icvWindowFrame, icvWindowFrame, dr3Right|dr3Bot);
		Val3dCtl(hwnd);
		}
	else {
	if (lStyle & WS_VSCROLL)
		{
		int SaveLeft;

		rc.xRight++;
		DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnHilite, dr3Right);
		rc.xRight--;
		SaveLeft = rc.xLeft;
		rc.xLeft = rc.xRight - GetSystemMetrics(SM_CXVSCROLL);
		DrawRec3d(hdc, &rc, icvWindowFrame, icvWindowFrame, dr3Bot);
		rc.xLeft = SaveLeft;
		}
	if (lStyle & WS_HSCROLL)
		{
		rc.yBot++;
		DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnHilite, dr3Bot);
		rc.yBot--;
		rc.yTop = rc.yBot - GetSystemMetrics(SM_CXHSCROLL);
		DrawRec3d(hdc, &rc, icvWindowFrame, icvWindowFrame, dr3Right);
		}
	}

	ReleaseDC(hwndParent, hdc);
	if (fEdit)
		ShowCaret(hwnd);

	}


LONG ShareEditComboWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, int ct)
	{
	LONG l;
	LONG style;

	if ( wm == WM_NCDESTROY )
	return CleanupSubclass(hwnd, wm, wParam, lParam, ct);

	if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
	return CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);

	l = CallWindowProc(LpfnGetDefWndProc(hwnd,ct), hwnd, wm, wParam, lParam);
	if (ct == ctCombo)
	{
		style = GetWindowLong(hwnd, GWL_STYLE);
		if ((style & 0x0003) == CBS_DROPDOWN)
			return l;
	}

	switch(wm)
		{
	case WM_CHECKSUBCLASS_OLD:
	case WM_CHECKSUBCLASS:
		*(int FAR *)lParam = fTrue;
		return ctEdit+1000;

	case WM_SHOWWINDOW:
		if (g3d.verWindows < ver31 && wParam == 0)
			Inval3dCtl(hwnd, (WINDOWPOS FAR *) NULL);
		break;
	case WM_WINDOWPOSCHANGING:
		if (g3d.verWindows >= ver31)
			Inval3dCtl(hwnd, (WINDOWPOS FAR *) lParam);
		break;

	case WM_PAINT:
		{
		if (ct != ctCombo ||
		   (((style & 0x0003) == CBS_DROPDOWN) || ((style & 0x0003) == CBS_DROPDOWNLIST)))
			ListEditPaint3d(hwnd, TRUE, ct);
		}
		break;
		}
	return l;
	}


LRESULT __export _loadds WINAPI EditWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
	{
	return ShareEditComboWndProc3d(hwnd, wm, wParam, lParam, ctEdit);
	}


LONG SharedListWndProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, unsigned ct)
	{
	LONG l;

	if ( wm == WM_NCDESTROY )
	return CleanupSubclass(hwnd, wm, wParam, lParam, ct);

	if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
	return CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);

	switch(wm)
		{
	case WM_CHECKSUBCLASS_OLD:
	case WM_CHECKSUBCLASS:
		*(int FAR *)lParam = fTrue;
		return ctList+1000;

	case WM_SHOWWINDOW:
		if (g3d.verWindows < ver31 && wParam == 0)
			Inval3dCtl(hwnd, (WINDOWPOS FAR *) NULL);
		break;
	case WM_WINDOWPOSCHANGING:
		if (g3d.verWindows >= ver31)
			Inval3dCtl(hwnd, (WINDOWPOS FAR *) lParam);
		break;
	case WM_PAINT:
        l = CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);
        ListEditPaint3d(hwnd, FALSE, ct);
		return l;
	case WM_NCCALCSIZE:
		{
		RC rc;		   
		RC rcNew;
		HWND hwndParent;

		// Inval3dCtl handles this case under Win 3.1
		if (g3d.verWindows >= ver31)
			break;

		GetWindowRect(hwnd, (LPRECT) &rc);		  
#ifdef UNREACHABLE
		if (g3d.verWindows >= ver31)
			{
			hwndParent = GetParent(hwnd);
			ScreenToClient(hwndParent, (LPPOINT) &rc);
			ScreenToClient(hwndParent, ((LPPOINT) &rc)+1);
			}
#endif

        l = CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);

		rcNew = *(RC FAR *)lParam;
		InflateRect((LPRECT) &rcNew, 2, 1); // +1 for border (Should use AdjustWindowRect)
		if (rcNew.yBot < rc.yBot)
			{
			rcNew.yTop = rcNew.yBot+1;
			rcNew.yBot = rc.yBot+1;

#ifdef ALWAYS
			if (g3d.verWindows < ver31)
#endif
				{
				hwndParent = GetParent(hwnd);
				ScreenToClient(hwndParent, (LPPOINT) &rcNew);
				ScreenToClient(hwndParent, ((LPPOINT) &rcNew)+1);
				}

			InvalidateRect(hwndParent, (LPRECT) &rcNew, TRUE);
			}
		return l;
		}
		}
    return CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);
	}

LRESULT __export _loadds WINAPI ListWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
	{
	return SharedListWndProc(hwnd, wm, wParam, lParam, ctList); 
	}



LRESULT __export _loadds WINAPI ComboWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
	{
	switch(wm)
		{
	case WM_CHECKSUBCLASS_OLD:
	case WM_CHECKSUBCLASS:
		*(int FAR *)lParam = fTrue;
		return ctCombo+1000;
		}

	return ShareEditComboWndProc3d(hwnd, wm, wParam, lParam, ctCombo);
	}

void StaticPrint(HWND hwnd, HDC hdc, RC FAR *lprc, LONG style)
	{
	WORD dt;
	LONG cv;
	Win16Or32(HANDLE , LPTSTR )hText;
	int TextLen;

	PatBlt(hdc, lprc->xLeft, lprc->yTop, lprc->xRight-lprc->xLeft, lprc->yBot-lprc->yTop, PATCOPY);

	TextLen = GetWindowTextLength(hwnd);

#ifndef WIN32
	hText = LocalAlloc(LPTR|LMEM_NODISCARD,(TextLen+5)*sizeof(TCHAR));
#else
	hText = _alloca((TextLen+5)*sizeof(TCHAR));
#endif
	if (hText == NULL)
		return;

	if (GetWindowText(hwnd, (NPTSTR)hText, TextLen+2*sizeof(TCHAR)) == 0)
	{
#ifndef WIN32
		LocalFree(hText);
#endif
		return;
	}
	
	if ((style & 0x000f) == SS_LEFTNOWORDWRAP)
		dt = DT_NOCLIP | DT_EXPANDTABS;
	else
		{
		dt = LOWORD(DT_NOCLIP | DT_EXPANDTABS | DT_WORDBREAK | ((style & 0x0000000f)-SS_LEFT));
		}

	if (style & SS_NOPREFIX)
		dt |= DT_NOPREFIX;

	if (style & WS_DISABLED)
		cv = SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);

	DrawText(hdc, (NPTSTR)hText, -1, (LPRECT) lprc, dt);

#ifndef WIN32
	LocalFree(hText);
#endif

	if (style & WS_DISABLED)
		cv = SetTextColor(hdc, cv);
	}

void StaticPaint(HWND hwnd, HDC hdc)
	{
	LONG style;
	RC rc;

	style = GetWindowLong(hwnd, GWL_STYLE);
	if(!(style & WS_VISIBLE))
		return;

	GetClientRect(hwnd, (LPRECT) &rc);
	switch(style & 0x1f)
		{
	case SS_BLACKRECT:
	case SS_BLACKFRAME:	 // Inset rect
		DrawRec3d(hdc, &rc, icvBtnShadow, icvBtnHilite, dr3All);
		break;
	case SS_GRAYRECT:
	case SS_GRAYFRAME:
	case 0x10:
	case 0x11:
	case 0x12:
		rc.xLeft++;
		rc.yTop++;
		DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnHilite, dr3All);
		OffsetRect((LPRECT) &rc, -1, -1);
		DrawRec3d(hdc, &rc, icvBtnShadow, icvBtnShadow, dr3All);
		break;
	case SS_WHITERECT:			  // outset rect
	case SS_WHITEFRAME:
		DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnShadow, dr3All);
		break;
	case SS_LEFT:
	case SS_CENTER:
	case SS_RIGHT:
	case SS_LEFTNOWORDWRAP:
		{
		HANDLE hfont;
		HBRUSH hbr;

		if((hfont = (HANDLE)SendMessage(hwnd, WM_GETFONT, 0, 0L)) != NULL)
			hfont = SelectObject(hdc, hfont);
		SetBkMode(hdc, OPAQUE);

		if(( hbr = SEND_COLOR_STATIC_MESSAGE(GetParent(hwnd), hwnd, hdc)) != NULL)
			hbr = SelectObject(hdc, hbr);

		StaticPrint(hwnd, hdc, (RC FAR *)&rc, style);

		if (hfont != NULL)
			SelectObject(hdc, hfont);

		if (hbr != NULL)
			SelectObject(hdc, hbr);
		}
		break;
		}
	}


LRESULT __export _loadds WINAPI StaticWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
	{
	HDC hdc;
	PAINTSTRUCT ps;

	if ( wm == WM_NCDESTROY )
	return CleanupSubclass(hwnd, wm, wParam, lParam, ctStatic);

	if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
	return CallWindowProc(LpfnGetDefWndProc(hwnd, ctStatic), hwnd, wm, wParam, lParam);

	switch (wm)
		{
	case WM_CHECKSUBCLASS_OLD:
	case WM_CHECKSUBCLASS:
		*(int FAR *)lParam = fTrue;
		return ctStatic+1000;

	case WM_PAINT:
		if ((hdc = (HDC) wParam) == NULL)
			{
			hdc = BeginPaint(hwnd, &ps);
			ClipCtlDc(hwnd, hdc);
			}
		StaticPaint(hwnd, hdc);
		if (wParam == (WPARAM)NULL)
			EndPaint(hwnd, &ps);
		return 0L;
		
	case WM_ENABLE:
		hdc = GetDC(hwnd);
		ClipCtlDc(hwnd, hdc);
		StaticPaint(hwnd, hdc);
		ReleaseDC(hwnd, hdc);
		return 0L;
		}
    return CallWindowProc(LpfnGetDefWndProc(hwnd, ctStatic), hwnd, wm, wParam, lParam);
	}


/*-----------------------------------------------------------------------
|   LibMain
-----------------------------------------------------------------------*/
#ifdef WIN32
#ifdef DLL
BOOL CALLBACK LibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
#else
#ifdef SDLL
BOOL FAR Ctl3dLibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
#else
BOOL FAR LibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
#endif
#endif
	{
	WORD wT;
	DWORD dwVersion;
	BOOL (WINAPI* pfnDisableThreadLibraryCalls)(HMODULE);
	HMODULE hKernel;

	switch(dwReason)
		{
	case DLL_PROCESS_ATTACH:
		// call DisableThreadLibraryCalls if available
		hKernel = GetModuleHandleA("KERNEL32.DLL");
		*(FARPROC*)&pfnDisableThreadLibraryCalls =
			GetProcAddress(hKernel, "DisableThreadLibraryCalls");
		if (pfnDisableThreadLibraryCalls != NULL)
			(*pfnDisableThreadLibraryCalls)(hModule);

#ifdef DLL
		InitializeCriticalSection(&g_CriticalSection);
#endif
		EnterCriticalSection(&g_CriticalSection);
#ifdef SDLL
		g3d.hinstLib = g3d.hmodLib = _hModule;
#else
		g3d.hinstLib = g3d.hmodLib = hModule;
#endif

		dwVersion = (DWORD)GetVersion();
		wT = LOWORD(dwVersion);
		// get adjusted windows version
		g3d.verWindows = (LOBYTE(wT) << 8) | HIBYTE(wT);
		// Win32s or Win32 for real (Chicago reports Win32s)
		g3d.verBase =
			(dwVersion & 0x80000000) && g3d.verWindows < ver40 ? 16 : 32;

		g3d.dxFrame = GetSystemMetrics(SM_CXDLGFRAME)-dxBorder;
		g3d.dyFrame = GetSystemMetrics(SM_CYDLGFRAME)-dyBorder;
		g3d.dyCaption = GetSystemMetrics(SM_CYCAPTION);
		g3d.dxSysMenu = GetSystemMetrics(SM_CXSIZE);

		LeaveCriticalSection(&g_CriticalSection);
		}
	return  TRUE;
	}
#else
#ifdef DLL
int WINAPI LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
#else
#ifdef SDLL
int FAR Ctl3dLibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
#else
#ifdef _BORLAND
BOOL FAR PASCAL LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
#else
BOOL FAR LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
#endif
#endif
#endif
	{
	WORD wT;
#ifdef DLL

#ifdef V2
	CodeLpszDeclA(lpszCtl3d, "CTL3DV2");
#else
	CodeLpszDeclA(lpszCtl3d, "CTL3D");
#endif

	CodeLpszDeclA(lpszUser, "user.exe");
	CodeLpszDeclA(lpszSetWindowsHookEx, "SETWINDOWSHOOKEX");
	CodeLpszDeclA(lpszUnhookWindowsHookEx, "UNHOOKWINDOWSHOOKEX");
	CodeLpszDeclA(lpszCallNextHookEx, "CALLNEXTHOOKEX");
#endif

	g3d.hinstLib = hModule;
#ifdef DLL
	g3d.hmodLib = GetModuleHandle(lpszCtl3d);
#else
#ifdef SDLL
	g3d.hinstLib = _hModule;
	g3d.hmodLib = GetModuleHandle(MAKELP(0,_hModule));
#else
	g3d.hmodLib = hModule;
#endif
#endif
	wT = LOWORD( GetVersion() );
	g3d.verWindows = (LOBYTE(wT) << 8) | HIBYTE(wT);

	if ( GetWinFlags() & 0x4000 )
		g3d.verBase = 24;		 // More then 16, not yet 32....WOW box on NT
	else
		g3d.verBase = 16;		 // Regular old 3.1

	g3d.dxFrame = GetSystemMetrics(SM_CXDLGFRAME)-dxBorder;
	g3d.dyFrame = GetSystemMetrics(SM_CYDLGFRAME)-dyBorder;
	g3d.dyCaption = GetSystemMetrics(SM_CYCAPTION);
	g3d.dxSysMenu = GetSystemMetrics(SM_CXSIZE);

#ifdef DLL
	if (g3d.verWindows >= ver31)
		{
		HANDLE hlib;

		hlib = LoadLibrary(lpszUser);
		if (FValidLibHandle(hlib))
			{
			(FARPROC) g3d.lpfnSetWindowsHookEx = GetProcAddress(hlib, lpszSetWindowsHookEx);
			(FARPROC) g3d.lpfnUnhookWindowsHookEx = GetProcAddress(hlib, lpszUnhookWindowsHookEx);
			(FARPROC) g3d.lpfnCallNextHookEx = GetProcAddress(hlib, lpszCallNextHookEx);
			FreeLibrary(hlib);
			}
		}
#endif
   return 1;
	}
#endif  // win32

// convert a RGB into a RGBQ
#define RGBQ(dw) RGB(GetBValue(dw),GetGValue(dw),GetRValue(dw))

//
//  LoadUIBitmap() - load a bitmap resource
//
//	 load a bitmap resource from a resource file, converting all
//	 the standard UI colors to the current user specifed ones.
//
//	 this code is designed to load bitmaps used in "gray ui" or
//	 "toolbar" code.
//
//	 the bitmap must be a 4bpp windows 3.0 DIB, with the standard
//	 VGA 16 colors.
//
//	 the bitmap must be authored with the following colors
//
//		Window Text      Black	   (index 0)
//		Button Shadow	  gray		(index 7)
//		Button Face	     lt gray   (index 8)
//		Button Highlight white	   (index 15)
//		Window Color	  yellow	   (index 11)
//		Window Frame	  green	   (index 10)
//
//	 Example:
//
//		hbm = LoadUIBitmap(hInstance, "TestBmp",
//			GetSysColor(COLOR_WINDOWTEXT),
//			GetSysColor(COLOR_BTNFACE),
//			GetSysColor(COLOR_BTNSHADOW),
//			GetSysColor(COLOR_BTNHIGHLIGHT),
//			GetSysColor(COLOR_WINDOW),
//			GetSysColor(COLOR_WINDOWFRAME));
//
//	 Author:	JimBov, ToddLa
//
//
#ifdef WIN32

HBITMAP PASCAL	LoadUIBitmap(
    HANDLE      hInstance,          // EXE file to load resource from
	LPCTSTR 	 szName,			 // name of bitmap resource
    COLORREF    rgbText,            // color to use for "Button Text"
    COLORREF    rgbFace,            // color to use for "Button Face"
    COLORREF    rgbShadow,          // color to use for "Button Shadow"
    COLORREF    rgbHighlight,       // color to use for "Button Hilight"
    COLORREF    rgbWindow,          // color to use for "Window Color"
    COLORREF    rgbFrame)           // color to use for "Window Frame"
{
    HBITMAP             hbm;
    LPBITMAPINFO        lpbi;
    HRSRC               hrsrc;
    HGLOBAL             h;
    HDC                 hdc;
    DWORD               size;

    //
    // Load the bitmap resource and make a writable copy.
    //

    hrsrc = FindResource(hInstance, szName, RT_BITMAP);
    if (!hrsrc)
        return(NULL);
    size = SizeofResource( hInstance, hrsrc );
    h = LoadResource(hInstance,hrsrc);
    if (!h)
        return(NULL);

    lpbi = ( LPBITMAPINFO ) GlobalAlloc( GPTR, size );

    if (!lpbi)
        return(NULL);

    CopyMemory( lpbi, h, size );

	*( LPCOLORREF ) &lpbi->bmiColors[0]  = RGBQ(rgbText);			// Black
	*( LPCOLORREF ) &lpbi->bmiColors[7]  = RGBQ(rgbShadow); 	   // gray
	*( LPCOLORREF ) &lpbi->bmiColors[8]  = RGBQ(rgbFace);		   // lt gray
	*( LPCOLORREF ) &lpbi->bmiColors[15] = RGBQ(rgbHighlight);	   // white
	*( LPCOLORREF ) &lpbi->bmiColors[11] = RGBQ(rgbWindow); 	   // yellow
	*( LPCOLORREF ) &lpbi->bmiColors[10] = RGBQ(rgbFrame);		   // green

    hdc = GetDC(NULL);

    hbm = CreateDIBitmap(hdc, &lpbi->bmiHeader, CBM_INIT, (LPBYTE)(&lpbi->bmiColors[ 16 ]),
            lpbi, DIB_RGB_COLORS);

    ReleaseDC(NULL, hdc);
    GlobalFree( lpbi );

    return(hbm);
}

#else

HBITMAP PASCAL	LoadUIBitmap(
		HANDLE		hInstance,		// EXE file to load resource from
		LPCTSTR 	szName,		   // name of bitmap resource
		COLORREF	rgbText,		  // color to use for "Button Text"
		COLORREF	rgbFace,		  // color to use for "Button Face"
		COLORREF	rgbShadow,		// color to use for "Button Shadow"
		COLORREF	rgbHighlight,	  // color to use for "Button Hilight"
		COLORREF	rgbWindow,		// color to use for "Window Color"
		COLORREF	rgbFrame)		 // color to use for "Window Frame"
	{
   LPBYTE			lpb;
	HBITMAP		   hbm;
	LPBITMAPINFOHEADER  lpbi;
	HANDLE			h;
	HDC			  hdc;
	LPDWORD		   lprgb;

	h = LoadResource(hInstance,FindResource(hInstance, szName, RT_BITMAP));

	lpbi = (LPBITMAPINFOHEADER)LockResource(h);

	if (!lpbi)
	   return(NULL);

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

	if (lpbi->biBitCount != 4)
	   return NULL;
#endif

	lprgb = (LPDWORD)((LPBYTE)lpbi + (int)lpbi->biSize);
	lpb   = (LPBYTE)(lprgb + 16);

	lprgb[0]  = RGBQ(rgbText);		// Black

//	lprgb[7]  = RGBQ(rgbFace);		// lt gray
//	lprgb[8]  = RGBQ(rgbShadow);	// gray

	lprgb[7]  = RGBQ(rgbShadow);	// gray
	lprgb[8]  = RGBQ(rgbFace);		// lt gray

	lprgb[15] = RGBQ(rgbHighlight);	// white
	lprgb[11] = RGBQ(rgbWindow);	// yellow
	lprgb[10] = RGBQ(rgbFrame);		// green

	hdc = GetDC(NULL);

	hbm = CreateDIBitmap(hdc, lpbi, CBM_INIT, (LPVOID)lpb,
	   (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);

	ReleaseDC(NULL, hdc);
	UnlockResource(h);
	FreeResource(h);

	return(hbm);
	}


#endif  // win32


/*-----------------------------------------------------------------------
|	
| DLL specific routines
|	
---------------------------------------------------------------WESC----*/

#ifndef WIN32
#ifdef DLL
/*-----------------------------------------------------------------------
|   WEP
-----------------------------------------------------------------------*/
int FAR PASCAL WEP (int wSystemExit)
	{
   return 1;
	}
#endif
#endif
