Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2994 lines
85 KiB

/*----------------------------------------------------------------------------*\
* GDIHELP.C - GDI TOOLHELP
*
* a bunch of GDI utility functions that are usefull for walking
* all GDI objects and dinking with them.
*
* ToddLa
*
\*----------------------------------------------------------------------------*/
#ifdef IS_16
#define DIRECT_DRAW
#endif
#ifdef DIRECT_DRAW
#include "ddraw16.h"
#else
#include <windows.h>
#include "gdihelp.h"
#include "dibeng.inc"
#ifdef DEBUG
#include <toolhelp.h>
#endif
#endif
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
#undef DPF
#ifdef DEBUG
static void CDECL DPF(char *sz, ...)
{
char ach[128];
lstrcpy(ach,"QuickRes: ");
wvsprintf(ach+10, sz, (LPVOID)(&sz+1));
#ifdef DIRECT_DRAW
dprintf(2, ach);
#else
lstrcat(ach, "\r\n");
OutputDebugString(ach);
#endif
}
static void NEAR PASCAL __Assert(char *exp, char *file, int line)
{
DPF("Assert(%s) failed at %s line %d.", (LPSTR)exp, (LPSTR)file, line);
DebugBreak();
}
#define Assert(exp) ( (exp) ? (void)0 : __Assert(#exp,__FILE__,__LINE__) )
#else
#define Assert(f)
#define DPF ; / ## /
#endif
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
extern HMODULE WINAPI GetExePtr(HANDLE h);
extern HANDLE WINAPI SetObjectOwner(HGDIOBJ, HANDLE);
extern BOOL WINAPI MakeObjectPrivate(HANDLE hObj, BOOL bPrivate);
extern int WINAPI GDISelectPalette(HDC, HPALETTE, BOOL);
#define PresDC(hdc) GetSystemPaletteUse(hdc)
void SaveDCFix(HGDIOBJ h, LPARAM lParam);
void SaveDCReSelectObjects(HGDIOBJ h, LPARAM lParam);
void ReRealizeObject(HGDIOBJ h, LPARAM lParam);
void ReSelectObjects(HGDIOBJ h, LPARAM lParam);
typedef struct {
BITMAPINFOHEADER bi;
DWORD ct[16];
} DIB4;
typedef struct {
BITMAPINFOHEADER bi;
DWORD ct[256];
} DIB8;
typedef struct {
HGDIOBJ h;
UINT type;
} GDIOBJECT, NEAR *GDIOBJECTLIST;
GDIOBJECTLIST GdiObjectList;
WORD GetW(HGDIOBJ h, UINT off);
WORD SetW(HGDIOBJ h, UINT off, WORD w);
/*----------------------------------------------------------------------------*\
* StockBitmap
* return the stock 1x1x1 bitmap, windows should have a GetStockObject for
* this but it does not.
\*----------------------------------------------------------------------------*/
HBITMAP StockBitmap()
{
HBITMAP hbm = CreateBitmap(0,0,1,1,NULL);
SetObjectOwner(hbm, 0);
return hbm;
}
/*----------------------------------------------------------------------------*\
* SafeSelectObject
*
* call SelectObject, but make sure USER does not RIP because we are using
* a DC without calling GetDC.
\*----------------------------------------------------------------------------*/
HGDIOBJ SafeSelectObject(HDC hdc, HGDIOBJ h)
{
UINT hf;
// this prevents USER from RIPing because we are using
// DCs in the cache without calling GetDC()
hf = SetHookFlags(hdc, DCHF_VALIDATEVISRGN);
h = SelectObject(hdc, h);
SetHookFlags(hdc, hf);
return h;
}
/*----------------------------------------------------------------------------*\
* IsMemoryDC
*
* return TRUE if the passed DC is a memory DC. we do this seeing if we
* can select the stock bitmap into it.
\*----------------------------------------------------------------------------*/
BOOL IsMemoryDC(HDC hdc)
{
HBITMAP hbm;
if (hbm = (HBITMAP)SafeSelectObject(hdc, StockBitmap()))
SafeSelectObject(hdc, hbm);
return hbm != NULL;
}
/*----------------------------------------------------------------------------*\
* IsScreenDC
*
* return TRUE for a non-memory DC
\*----------------------------------------------------------------------------*/
BOOL IsScreenDC(HDC hdc)
{
return (!IsMemoryDC(hdc) && GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY);
}
/*----------------------------------------------------------------------------*\
* GetObjectOwner
* return the owner of a GDI object
\*----------------------------------------------------------------------------*/
HANDLE GetObjectOwner(HGDIOBJ h)
{
HANDLE owner;
owner = SetObjectOwner(h, 0);
SetObjectOwner(h, owner);
return owner;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
BOOL IsObjectPrivate(HGDIOBJ h)
{
BOOL IsPrivate;
IsPrivate = MakeObjectPrivate(h, 0);
MakeObjectPrivate(h, IsPrivate);
return IsPrivate;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
BOOL IsObjectStock(HGDIOBJ h)
{
int n;
for (n=0; n<=17; n++)
if (GetStockObject(n) == h)
return TRUE;
if (StockBitmap() == h)
return TRUE;
return FALSE;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
#pragma optimize("", off)
UINT GetGdiDS()
{
UINT result;
IsGDIObject((HGDIOBJ)1);
_asm mov ax,es
_asm mov result,ax
#ifdef DEBUG
{
SYSHEAPINFO shi = {sizeof(shi)};
SystemHeapInfo(&shi);
Assert((UINT)shi.hGDISegment == result);
}
#endif
return result;
}
#pragma optimize("", on)
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
GDIOBJECTLIST BuildGdiObjectList(void)
{
int i;
int count;
GDIOBJECTLIST list;
UINT type;
UINT hgdi = GetGdiDS();
#ifdef DEBUG
UINT ObjHist[OBJ_MAX+1];
for (i=0; i<=OBJ_MAX; i++) ObjHist[i] = 0;
#endif
DPF("BEGIN BuildGdiObjectList...");
i=0;
count=0;
list=NULL;
again:
{
WORD FAR *pw;
UINT cnt;
HANDLE h;
// get pointer to local heap info (stored at offset 6 in DGROUP)
pw = MAKELP(hgdi, 6);
pw = MAKELP(hgdi, *pw);
// get pointer to first handle table (stored at offset 0x14 in HeapInfo)
pw = MAKELP(hgdi, pw[0x14/2]);
//
// a handle table starts with a WORD count of entries, followed
// by the entries (each is a DWORD) last WORD is a pointer to
// the next handle table or 0.
//
// each handle entry is a WORD ptr, followed by flags (WORD)
// the HIBYTE of the flags is realy the lock count.
// if the flags are 0xFFFF the handle is free.
// for the GDI heap if 0x10 is set in the flags the
// handle is a GDI object handle.
//
while (OFFSETOF(pw) != 0)
{
cnt = *pw++; // get handle table count
while (cnt-- > 0)
{
h = (HANDLE)OFFSETOF(pw);
// is the handle free? yes skip
if (pw[1] != 0xFFFF)
{
// is the handle a GDI object?
if (pw[1] & 0x0010)
{
type = (UINT)IsGDIObject(h);
if (type)
{
if (list)
{
Assert(i >= 0 && i < count);
list[i].h = (HGDIOBJ)h;
list[i].type = type;
i++;
}
else
{
count++;
#ifdef DEBUG
Assert(type > 0 && type <= OBJ_MAX);
ObjHist[type]++;
#endif
}
}
}
// not a gdi object, might be a SaveDC
else
{
if ((UINT)IsGDIObject(h) == OBJ_DC)
{
if (list)
{
Assert(i >= 0 && i < count);
list[i].h = (HGDIOBJ)h;
list[i].type = OBJ_SAVEDC;
i++;
}
else
{
count++;
#ifdef DEBUG
ObjHist[OBJ_SAVEDC]++;
#endif
}
}
}
}
pw += 2; // next handle
}
// get next handle table.
pw = MAKELP(hgdi,*pw);
}
}
if (list == NULL)
{
list = (GDIOBJECTLIST)LocalAlloc(LPTR, sizeof(GDIOBJECT) * (count+1));
if (list == NULL)
{
Assert(0);
return NULL;
}
goto again;
}
Assert(i == count);
list[i].h = NULL; // NULL terminate list
list[i].type = 0; // NULL terminate list
DPF("END BuildGdiObjectList %d objects.", count);
DPF(" DC: %d", ObjHist[OBJ_DC]);
DPF(" SaveDC: %d", ObjHist[OBJ_SAVEDC]);
DPF(" Bitmap: %d", ObjHist[OBJ_BITMAP]);
DPF(" Pen: %d", ObjHist[OBJ_PEN]);
DPF(" Palette:%d", ObjHist[OBJ_PALETTE]);
DPF(" Brush: %d", ObjHist[OBJ_BRUSH]);
DPF(" Total: %d", count);
return list;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
BOOL BeginGdiSnapshot(void)
{
if (GdiObjectList != NULL)
return TRUE;
GdiObjectList = BuildGdiObjectList();
return GdiObjectList != NULL;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
void EndGdiSnapshot(void)
{
if (GdiObjectList != NULL)
{
LocalFree((HLOCAL)GdiObjectList);
GdiObjectList = NULL;
}
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
void EnumGdiObjects(UINT type, EnumGdiObjectsCallback callback, LPARAM lParam)
{
int i;
Assert(GdiObjectList != NULL);
if (GdiObjectList == NULL)
return;
for (i=0; GdiObjectList[i].h; i++)
{
if (GdiObjectList[i].type == type)
{
(*callback)(GdiObjectList[i].h, lParam);
}
}
}
#ifdef DEBUG
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
LPCSTR GetObjectOwnerName(HGDIOBJ hgdi)
{
int i;
HMODULE hModule;
HANDLE h = GetObjectOwner(hgdi);
static char ach[80];
if (h == 0)
return "System";
else if (h == (HANDLE)1)
return "Orphan";
else if (hModule = (HMODULE)GetExePtr(h))
{
GetModuleFileName(hModule, ach, sizeof(ach));
for (i=lstrlen(ach); i>0 && ach[i-1]!='\\'; i--)
;
return ach+i;
}
else
{
wsprintf(ach, "#%04X", h);
return ach;
}
}
#endif
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
HBITMAP CurrentBitmap(HDC hdc)
{
HBITMAP hbm;
if (hbm = SafeSelectObject(hdc, StockBitmap()))
SafeSelectObject(hdc, hbm);
return hbm;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
HBRUSH CurrentBrush(HDC hdc)
{
HBRUSH hbr;
if (hbr = SafeSelectObject(hdc, GetStockObject(BLACK_BRUSH)))
SafeSelectObject(hdc, hbr);
return hbr;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
HPEN CurrentPen(HDC hdc)
{
HPEN pen;
if (pen = SafeSelectObject(hdc, GetStockObject(BLACK_PEN)))
SafeSelectObject(hdc, pen);
return pen;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
HPALETTE CurrentPalette(HDC hdc)
{
HPALETTE hpal;
if (hpal = SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE))
SelectPalette(hdc, hpal, FALSE);
return hpal;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
HDC GetBitmapDC(HBITMAP hbm)
{
int i;
HDC hdc;
HBITMAP hbmT;
Assert(GdiObjectList != NULL);
hdc = CreateCompatibleDC(NULL);
hbmT = SelectObject(hdc, hbm);
DeleteDC(hdc);
//
// if we can select this bitmap into a memDC, it is not selected.
// into any other DC
//
if (hbmT != NULL)
return NULL;
if (GdiObjectList == NULL)
return NULL;
for (i=0; GdiObjectList[i].h; i++)
{
if (GdiObjectList[i].type == OBJ_DC)
{
if (CurrentBitmap((HDC)GdiObjectList[i].h) == hbm)
return GdiObjectList[i].h;
}
}
return NULL;
}
/*----------------------------------------------------------------------------*\
* GetObjectPalette
\*----------------------------------------------------------------------------*/
HPALETTE GetObjectPalette(HGDIOBJ h)
{
HANDLE owner = GetObjectOwner(h);
HPALETTE hpal;
HPALETTE hpal20=NULL;
HPALETTE hpal256=NULL;
HPALETTE hpalDef = GetStockObject(DEFAULT_PALETTE);
int i;
int count20;
int count256;
Assert(GdiObjectList != NULL);
//
// look at all the palettes owned by the app
// mabey if we are lucky there will only be one.
//
for (i=count20=count256=0; GdiObjectList[i].h; i++)
{
if (GdiObjectList[i].type == OBJ_PALETTE)
{
hpal=(HPALETTE)GdiObjectList[i].h;
if (hpal == hpalDef)
continue;
if (GetObjectOwner(hpal) == owner)
{
int n = 0;
GetObject(hpal, sizeof(n), &n);
if (n > 20)
{
count256++;
hpal256 = hpal;
}
else
{
count20++;
hpal20 = hpal;
}
}
}
}
if (count256 == 1)
{
DPF("got palette (%04X) because app (%s) only has one palette", hpal256, GetObjectOwnerName(h));
return hpal256;
}
if (count256 == 2 && count20 == 0)
{
DPF("got palette (%04X) because app (%s) only has two palettes", hpal256, GetObjectOwnerName(h));
return hpal256;
}
if (count20 == 1 && count256 == 0)
{
DPF("got palette (%04X) because app (%s) only has one palette", hpal20, GetObjectOwnerName(h));
return hpal20;
}
if (count20 == 0 && count256 == 0)
{
DPF("no palette for (%04X) because app (%s) has none.", h, GetObjectOwnerName(h));
return GetStockObject(DEFAULT_PALETTE);
}
DPF("**** cant find palette for (%04X) ****", h);
return NULL;
}
/*----------------------------------------------------------------------------*\
* GetBitmapPalette
*
* try to find out the palette that the given DDB uses, this is done be a series
* of hacks and it only works some of the time.
*
\*----------------------------------------------------------------------------*/
HPALETTE GetBitmapPalette(HBITMAP hbm)
{
BITMAP bm;
DWORD dw;
HDC hdc;
HPALETTE hpal;
HPALETTE hpalClip=NULL;
HBITMAP hbmClip=NULL;
Assert(GdiObjectList != NULL);
//
// get the bitmap info, if it is not a bitmap palette is NULL
//
if (GetObject(hbm, sizeof(bm), &bm) == 0)
return NULL;
//
// DIBSections dont have or need palettes
//
if (bm.bmBits != NULL)
return NULL;
//
// 8 bit DDBs are the only bitmaps that care about palettes
//
if (bm.bmBitsPixel != 8 || bm.bmPlanes != 1)
return NULL;
//
// with a new DIBENG it will give us the palette
// in the bitmap dimension, what a hack
//
dw = GetBitmapDimension(hbm);
if (dw && IsGDIObject((HGDIOBJ)HIWORD(dw)) == OBJ_PALETTE &&
HIWORD(dw) != (UINT)GetStockObject(DEFAULT_PALETTE))
{
DPF("got palette (%04X) from the DIBENG", HIWORD(dw), hbm);
return (HPALETTE)HIWORD(dw);
}
//
// if the bitmap is on the clipboard we know what palette to use
//
if (IsClipboardFormatAvailable(CF_PALETTE))
{
if (OpenClipboard(NULL))
{
hpalClip = GetClipboardData(CF_PALETTE);
hbmClip = GetClipboardData(CF_BITMAP);
CloseClipboard();
}
if (hbm == hbmClip)
{
DPF("got palette (%04X) from the clipboard", hpalClip);
return hpalClip;
}
}
//
// try to find a palette by looking at palettes owned by the app.
//
hpal = GetObjectPalette(hbm);
//
// we can figure out the palette of the app, return it
//
if (hpal)
{
if (hpal == GetStockObject(DEFAULT_PALETTE))
return NULL;
else
return hpal;
}
//
// if the bitmap is selected into a memoryDC check to see if
// the memoryDC has a palette.
//
if ((hdc = GetBitmapDC(hbm)) && (hpal = CurrentPalette(hdc)))
{
if (hpal != GetStockObject(DEFAULT_PALETTE))
{
DPF("got palette (%04X) from memDC (%04X)", hpal, hdc);
return hpal;
}
}
DPF("**** cant find palette for bitmap (%04X) ****", hbm);
return NULL;
}
/*----------------------------------------------------------------------------*\
* ConvertDDBtoDS
*
* converts a DDB to a DIBSection
* the conversion is done in place so the handle does not change.
\*----------------------------------------------------------------------------*/
HBITMAP ConvertDDBtoDS(HBITMAP hbm)
{
BITMAP bm;
HBITMAP hbmT;
HDC hdc;
HDC hdcSel;
HPALETTE hpal;
LPVOID lpBits;
HANDLE owner;
BOOL IsPrivate;
int i;
DWORD size;
DIB8 dib;
UINT SelCount;
DWORD dw;
if (GetObject(hbm, sizeof(bm), &bm) == 0)
return NULL;
if (bm.bmBits)
return NULL;
if (bm.bmPlanes == 1 && bm.bmBitsPixel == 1)
return NULL;
dw = GetBitmapDimension(hbm);
owner = GetObjectOwner(hbm);
// if (owner == 0)
// return NULL;
hpal = GetBitmapPalette(hbm);
hdc = GetDC(NULL);
if (hpal)
{
SelectPalette(hdc, hpal, TRUE);
RealizePalette(hdc);
}
dib.bi.biSize = sizeof(BITMAPINFOHEADER);
dib.bi.biBitCount = 0;
GetDIBits(hdc, hbm, 0, 1, NULL, (LPBITMAPINFO)&dib.bi, DIB_RGB_COLORS);
GetDIBits(hdc, hbm, 0, 1, NULL, (LPBITMAPINFO)&dib.bi, DIB_RGB_COLORS);
dib.bi.biXPelsPerMeter = 0x42424242; // special flag marking a DDB
dib.bi.biHeight = -bm.bmHeight; // top-down DIB
if (hpal)
SelectPalette(hdc, (HPALETTE)GetStockObject(DEFAULT_PALETTE), TRUE);
// we dont have a palette, best guess is the system palette
if (hpal == NULL && (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE))
{
DPF("Converting DDB(%04X) to DS for %s (using syspal)", hbm, GetObjectOwnerName(hbm));
GetSystemPaletteEntries(hdc, 0, 256, (LPPALETTEENTRY)dib.ct);
for (i=0; i<256; i++)
dib.ct[i] = RGB(GetBValue(dib.ct[i]), GetGValue(dib.ct[i]), GetRValue(dib.ct[i]));
}
else if (hpal)
{
DPF("Converting DDB(%04X) to DS for %s, using palette (%04X)", hbm, GetObjectOwnerName(hbm), hpal);
}
else
{
DPF("Converting DDB(%04X) to DS for %s", hbm, GetObjectOwnerName(hbm));
}
ReleaseDC(NULL, hdc);
size = (DWORD)bm.bmWidthBytes * bm.bmHeight;
lpBits = GlobalAllocPtr(GHND, size);
Assert(lpBits != NULL);
if (lpBits == NULL)
return NULL;
GetBitmapBits(hbm, size, lpBits);
IsPrivate = MakeObjectPrivate(hbm, FALSE);
hdcSel = GetBitmapDC(hbm);
if (hdcSel)
SelectObject(hdcSel, StockBitmap());
SelCount = GetW(hbm, 16);
if (SelCount != 0)
{
DPF("***** bitmap %04X select count is %d, must be in a SaveDC block!", hbm, SelCount);
SetW(hbm, 16, 0);
}
DeleteBitmap(hbm);
if (IsGDIObject(hbm))
{
DPF("***** UNABLE TO DELETE bitmap %04X *****", hbm);
Assert(0);
}
else
{
hbmT = CreateDIBSection(NULL, (LPBITMAPINFO)&dib.bi, DIB_RGB_COLORS, NULL, NULL, 0);
Assert(hbmT == hbm);
SetBitmapBits(hbm, size, lpBits);
}
GlobalFreePtr(lpBits);
if (SelCount)
SetW(hbm, 16, SelCount);
SetObjectOwner(hbm, owner);
MakeObjectPrivate(hbm, IsPrivate);
if (hdcSel)
SelectObject(hdcSel, hbm);
SetBitmapDimension(hbm, LOWORD(dw), HIWORD(dw));
return hbm;
}
/*----------------------------------------------------------------------------*\
* Convert DStoDDB
*
* convert a DIBSection back to a DDB, we only do this if the DIBSection
* came from a DDB (ConvertDDBtoDS puts a magic value in biXPelsPerMeter)
* the conversion is done in place so the handle does not change.
\*----------------------------------------------------------------------------*/
HBITMAP ConvertDStoDDB(HBITMAP hbm, BOOL fForceConvert)
{
struct {
BITMAP bm;
BITMAPINFOHEADER bi;
DWORD ct[256];
} ds;
HDC hdcSel;
HDC hdc;
HBITMAP hbmT;
HANDLE owner;
BOOL IsPrivate;
LPVOID lpBits;
DWORD size;
int planes,bpp,rc;
UINT SelCount;
DWORD dw;
hdc = GetDC(NULL);
bpp = GetDeviceCaps(hdc, BITSPIXEL);
planes = GetDeviceCaps(hdc, PLANES);
rc = GetDeviceCaps(hdc, RASTERCAPS);
ReleaseDC(NULL, hdc);
if (GetObject(hbm, sizeof(ds), &ds) == 0)
return NULL;
if (ds.bm.bmBits == NULL)
return NULL;
if (ds.bm.bmBitsPixel == 1)
return NULL;
if (ds.bi.biXPelsPerMeter != 0x42424242)
return NULL;
if (ds.bi.biHeight >= 0)
return NULL;
//
// HACK we want to convert bitmaps that are exactly 8x8
// back to DDBs always. Win95 GDI does not support
// Creating a pattern brush from a DIBSection so
// we must do this.
//
if (ds.bm.bmWidth == 8 && ds.bm.bmHeight == 8)
{
DPF("Converting 8x8 DS(%04X) back to DDB for %s", hbm, GetObjectOwnerName(hbm));
fForceConvert = TRUE;
}
//
// unless force convert is TRUE we only want to be here in 8bpp mode.
//
if (!fForceConvert && !(rc & RC_PALETTE))
return NULL;
if (!fForceConvert && (ds.bm.bmPlanes != planes || ds.bm.bmBitsPixel != bpp))
return NULL;
dw = GetBitmapDimension(hbm);
owner = GetObjectOwner(hbm);
// if (owner == 0)
// return NULL;
DPF("Converting DS(%04X) %dx%dx%d to DDB for %s", hbm, ds.bm.bmWidth, ds.bm.bmHeight, ds.bm.bmBitsPixel, GetObjectOwnerName(hbm));
hdcSel = GetBitmapDC(hbm);
size = (DWORD)ds.bm.bmWidthBytes * ds.bm.bmHeight;
lpBits = GlobalAllocPtr(GHND, size);
Assert(lpBits != NULL);
if (lpBits == NULL)
return NULL;
IsPrivate = MakeObjectPrivate(hbm, FALSE);
if (hdcSel)
SelectObject(hdcSel, StockBitmap());
hdc = GetDC(NULL);
if (ds.bm.bmPlanes == planes && ds.bm.bmBitsPixel == bpp)
GetBitmapBits(hbm, size, lpBits);
else
GetDIBits(hdc, hbm, 0, ds.bm.bmHeight, lpBits, (LPBITMAPINFO)&ds.bi, DIB_RGB_COLORS);
SelCount = GetW(hbm, 16);
if (SelCount != 0)
{
DPF("bitmap %04X select count is %d, must be in a SaveDC block!", hbm, SelCount);
SetW(hbm, 16, 0);
}
DeleteBitmap(hbm);
if (IsGDIObject(hbm))
{
DPF("***** UNABLE TO DELETE bitmap %04X *****", hbm);
Assert(0);
}
else
{
hbmT = CreateCompatibleBitmap(hdc,ds.bm.bmWidth,ds.bm.bmHeight);
Assert(hbmT == hbm);
if (ds.bm.bmPlanes == planes && ds.bm.bmBitsPixel == bpp)
SetBitmapBits(hbm, size, lpBits);
else
SetDIBits(hdc, hbm, 0, ds.bm.bmHeight, lpBits, (LPBITMAPINFO)&ds.bi, DIB_RGB_COLORS);
}
ReleaseDC(NULL, hdc);
GlobalFreePtr(lpBits);
if (SelCount)
SetW(hbm, 16, SelCount);
SetObjectOwner(hbm, owner);
MakeObjectPrivate(hbm, IsPrivate);
if (hdcSel)
SelectObject(hdcSel, hbm);
SetBitmapDimension(hbm, LOWORD(dw), HIWORD(dw));
return hbm;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
void FlushGdiXlatCache()
{
DIB8 dib;
HDC hdc;
HBITMAP hbm;
if (hbm = CreateBitmap(1,1,1,1,NULL))
{
if (hdc = CreateCompatibleDC(NULL))
{
SelectBitmap(hdc, hbm);
dib.bi.biSize = sizeof(BITMAPINFOHEADER);
dib.bi.biWidth = 1;
dib.bi.biHeight = 1;
dib.bi.biPlanes = 1;
dib.bi.biCompression = 0;
dib.bi.biSizeImage = 0;
dib.bi.biXPelsPerMeter = 0;
dib.bi.biYPelsPerMeter = 0;
dib.bi.biClrUsed = 2;
dib.bi.biClrImportant = 0;
dib.ct[0] = RGB(1,1,1);
dib.ct[2] = RGB(2,2,2);
for (dib.bi.biBitCount = 1;
dib.bi.biBitCount <= 8;
dib.bi.biBitCount = (dib.bi.biBitCount + 4) & ~1)
{
SetDIBits(hdc, hbm, 0, 1, (LPVOID)&dib.bi,
(LPBITMAPINFO)&dib.bi, DIB_PAL_COLORS);
}
DeleteDC(hdc);
}
DeleteBitmap(hbm);
}
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
void ReSelectObjects(HGDIOBJ h, LPARAM lParam)
{
COLORREF rgb;
UINT hf;
HDC hdc = (HDC)h;
////DPF("ReSelecting objects for DC %04X", h);
// this prevents USER from RIPing because we are using
// DCs in the cache without calling GetDC()
hf = SetHookFlags(hdc, DCHF_VALIDATEVISRGN);
SelectObject(hdc, SelectObject(hdc, GetStockObject(BLACK_BRUSH)));
SelectObject(hdc, SelectObject(hdc, GetStockObject(BLACK_PEN)));
GDISelectPalette(hdc, GDISelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), TRUE), TRUE);
rgb = GetTextColor(hdc);
SetTextColor(hdc, rgb ^ 0xFFFFFF);
SetTextColor(hdc, rgb);
rgb = GetBkColor(hdc);
SetBkColor(hdc, rgb ^ 0xFFFFFF);
SetBkColor(hdc, rgb);
SetHookFlags(hdc, hf);
}
/////////////////////////////////////////////////////////////////////////////
//
// ReRealizeObjects
//
// calls ReRealizeObject for every pen/brush in the system, this makes sure
// all pens/brushs will be rerealized next time they are used.
//
// call ReSelectObjects() to make sure the current pen/brush/text colors
// are correct in all DCs
//
/////////////////////////////////////////////////////////////////////////////
void ReRealizeObjects()
{
BeginGdiSnapshot();
FlushGdiXlatCache();
EnumGdiObjects(OBJ_BRUSH, ReRealizeObject, 0);
EnumGdiObjects(OBJ_PEN, ReRealizeObject, 0);
EnumGdiObjects(OBJ_DC, ReSelectObjects, 0);
EnumGdiObjects(OBJ_SAVEDC,SaveDCFix, 0);
EnumGdiObjects(OBJ_SAVEDC,SaveDCReSelectObjects, 0);
EndGdiSnapshot();
}
/////////////////////////////////////////////////////////////////////////////
//
// ConvertObjects
//
// convert all DDBs to DIBSections
// convert all color pattern brush's to DIBPattern brushs
// convert all 8bpp icons to 4bpp icons.
//
/////////////////////////////////////////////////////////////////////////////
void ConvertBitmapCB(HGDIOBJ h, LPARAM lParam)
{
ConvertDDBtoDS(h);
}
void ConvertBrushCB(HGDIOBJ h, LPARAM lParam)
{
ConvertPatternBrush(h);
}
void ConvertObjects()
{
BeginGdiSnapshot();
EnumGdiObjects(OBJ_BITMAP, ConvertBitmapCB, 0);
EnumGdiObjects(OBJ_BRUSH, ConvertBrushCB, 0);
EndGdiSnapshot();
}
/////////////////////////////////////////////////////////////////////////////
//
// ConvertBitmapsBack
//
// convert all DIBSections to DDBs
//
/////////////////////////////////////////////////////////////////////////////
void ConvertBitmapBackCB(HGDIOBJ h, LPARAM lParam)
{
ConvertDStoDDB(h, (BOOL)lParam);
}
void ConvertBitmapsBack(BOOL fForceConvert)
{
BeginGdiSnapshot();
EnumGdiObjects(OBJ_BITMAP, ConvertBitmapBackCB, fForceConvert);
EndGdiSnapshot();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// BEGIN EVIL
//
// the next few functions mess directly with GDI code/data
//
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
LPWORD LockObj(HGDIOBJ h, UINT off)
{
WORD FAR *pw;
UINT hGDI = GetGdiDS();
pw = MAKELP(hGDI, h);
if (IsBadReadPtr(pw, 2))
return NULL;
pw = MAKELP(hGDI, *pw + off);
if (IsBadReadPtr(pw, 2))
return NULL;
return pw;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
WORD GetW(HGDIOBJ h, UINT off)
{
WORD FAR *pw;
if (pw = LockObj(h, off))
return *pw;
else
return 0;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
WORD SetW(HGDIOBJ h, UINT off, WORD w)
{
WORD FAR *pw;
WORD ret = 0;
if (pw = LockObj(h, off))
{
ret = *pw;
*pw = w;
}
return ret;
}
/*----------------------------------------------------------------------------*\
* ReRealizeObject
*
* delete all physical objects associated with the given GDI object
* this will guarentee the next time the brush/pen is selected we will
* have the device driver rerealize the object.
*
* there are a few ways to do this....
*
* method #1
* call SetSolidBrush()
* this only works for private/solid(not stock) brushes, not pens
* we need to save/restore the stock object bit.
* we need to save/restore the private bit.
*
* method #2
* delete the object and recreate it getting the same handle
* we need to patch the SelCount because we cant delete a selected obj
* we need to save/restore the stock object bit.
* we need to save/restore the private bit.
* we need to save/restore the owner.
*
* method #3
* create a temp object, move the physchain from the given object
* to the new object, delete the temp object.
* we need to patch phys chain of the objects.
*
* after deleting all the physical objects ReSelectObjects() should be
* called to clean up all the objects currently selected in all DCs
*
* SaveDCs are a pain in the neck, ReSelectObjects() does not deal with
* the SaveDC blocks floating around GDIs heap. we need to fix this
* in the general case, the system savedc's just have the white_brush
* and black_pen.
*
* currently using method #3
*
\*----------------------------------------------------------------------------*/
void ReRealizeObject(HGDIOBJ h, LPARAM lParam)
{
HGDIOBJ hTemp;
UINT type;
type = IsGDIObject(h);
//
// if the object does not have a physchain we have no work to do!
//
if (GetW(h, 0) == 0)
return;
//
// create a temp pen/brush so we can delete it and trick
// GDI into disposing all the phys objects.
//
if (type == OBJ_BRUSH)
hTemp = CreateSolidBrush(RGB(1,1,1));
else if (type == OBJ_PEN)
hTemp = CreatePen(PS_SOLID, 0, RGB(1,1,1));
else
return;
Assert(hTemp != NULL);
Assert(GetW(hTemp, 0) == 0);
if (type == OBJ_BRUSH)
DPF("ReRealize Brush %04X for %s", h, GetObjectOwnerName(h));
else
DPF("ReRealize Pen %04X for %s", h, GetObjectOwnerName(h));
//
// copy the phys chain from the passed in object to the
// temp object then call DeleteObject to free them.
//
SetW(hTemp, 0, GetW(h, 0));
SetW(h, 0, 0);
DeleteObject(hTemp);
return;
}
/*----------------------------------------------------------------------------*\
* ConvertPatternBrush
*
* convert a BS_PATTERN brush to a BS_DIBPATTERN brush.
* we only convert non-mono pattern brushes
\*----------------------------------------------------------------------------*/
HBRUSH ConvertPatternBrush(HBRUSH hbr)
{
LOGBRUSH lb;
HBITMAP hbm;
COLORREF c0, c1;
HDC hdc;
if (GetObject(hbr, sizeof(lb), &lb) == 0)
return NULL;
if (lb.lbStyle != BS_PATTERN)
return NULL;
hdc = GetDC(NULL);
hbm = CreateCompatibleBitmap(hdc, 8, 8);
ReleaseDC(NULL, hdc);
hdc = CreateCompatibleDC(NULL);
SelectObject(hdc, hbm);
SelectObject(hdc, hbr);
SetTextColor(hdc, 0x000000);
SetBkColor(hdc, 0x000000);
PatBlt(hdc, 0, 0, 8, 8, PATCOPY);
c0 = GetPixel(hdc, 0, 0);
SetTextColor(hdc, 0xFFFFFF);
SetBkColor(hdc, 0xFFFFFF);
PatBlt(hdc, 0, 0, 8, 8, PATCOPY);
c1 = GetPixel(hdc, 0, 0);
//
// if the brush is a mono pattern brush dont convert it
//
if (c0 == c1)
{
HANDLE h;
LPBITMAPINFOHEADER lpbi;
HBRUSH hbrT;
HANDLE owner;
BOOL IsPrivate;
WORD Flags;
HPALETTE hpal=NULL;
if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
{
hpal = GetObjectPalette(hbr);
if (hpal == GetStockObject(DEFAULT_PALETTE))
hpal = NULL;
}
if (hpal)
{
SelectPalette(hdc, hpal, TRUE);
RealizePalette(hdc);
PatBlt(hdc, 0, 0, 8, 8, PATCOPY);
DPF("Converting pattern brush %04X for %s (using hpal=%04X)", hbr, GetObjectOwnerName(hbr), hpal);
}
else
{
DPF("Converting pattern brush %04X for %s", hbr, GetObjectOwnerName(hbr));
}
h = GlobalAlloc(GHND, sizeof(BITMAPINFOHEADER) + 256*4 + 8*8*4);
Assert(h != NULL);
if (h == NULL)
return hbr;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(h);
lpbi->biSize = sizeof(BITMAPINFOHEADER);
lpbi->biBitCount = 0;
GetDIBits(hdc, hbm, 0, 1, NULL, (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
if (lpbi->biClrUsed == 0 && lpbi->biCompression == BI_BITFIELDS)
lpbi->biClrUsed = 3;
if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
lpbi->biClrUsed = (1 << lpbi->biBitCount);
GetDIBits(hdc, hbm, 0, (int)lpbi->biHeight,
(LPBYTE)lpbi + lpbi->biSize + lpbi->biClrUsed*sizeof(RGBQUAD),
(LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
owner = SetObjectOwner(hbr, 0);
IsPrivate = MakeObjectPrivate(hbr, FALSE);
Flags = SetW(hbr, 10, 0);
DeleteObject(hbr);
if (IsGDIObject(hbr))
{
DPF("***** UNABLE TO DELETE brush %04X *****", hbr);
Assert(0);
}
else
{
hbrT = CreateDIBPatternBrush(h, DIB_RGB_COLORS);
Assert(hbrT == hbr);
}
GlobalFree(h);
SetW(hbr, 10, Flags);
MakeObjectPrivate(hbr, IsPrivate);
SetObjectOwner(hbr, owner);
if (hpal)
{
SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), TRUE);
}
}
DeleteDC(hdc);
DeleteObject(hbm);
return hbr;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
LPVOID GetPDevice(HDC hdc)
{
DWORD FAR *pdw;
Assert(IsGDIObject(hdc) == OBJ_DC);
if (IsGDIObject(hdc) != OBJ_DC)
return NULL;
PresDC(hdc);
if (pdw = (DWORD FAR *)LockObj(hdc, 0x30))
return (LPVOID)*pdw;
else
return NULL;
////return MAKELP(GetW(hdc, 0x32), GetW(hdc, 0x30));
}
/*----------------------------------------------------------------------------*\
*
* get the "internal" version of a GDI api
* we need to do this so we can call GDI APIs like SelectObject and
* SetTextColor on SaveDC blocks.
*
* we only need to do this on SaveDC blocks, not every DC
*
* the code must look like this or we fail:
*
* RealProc:
* .....
* JMP #### <== Internal version of RealProc
* mov dh,80 (optinal)
* RETF NumParams
* NextProc:
*
\*----------------------------------------------------------------------------*/
FARPROC GetInternalProc(FARPROC RealProc, FARPROC NextProc, UINT NumParams)
{
LPBYTE pb = (LPBYTE)NextProc;
if ((DWORD)NextProc == 0 ||
(DWORD)RealProc == 0 ||
LOWORD(RealProc) <= 6 ||
(DWORD)NextProc <= (DWORD)RealProc ||
((DWORD)NextProc - (DWORD)RealProc) > 80)
{
Assert(0);
return RealProc;
}
if (pb[-6] == 0xE9 && pb[-3] == 0xCA && pb[-2] == NumParams && pb[-1] == 0x00)
{
return (FARPROC)MAKELP(SELECTOROF(pb), OFFSETOF(pb)-3+*(WORD FAR *)(pb-5));
}
if (pb[-8] == 0xE9 && pb[-5] == 0xB6 && pb[-4] == 0x80 &&
pb[-3] == 0xCA && pb[-2] == NumParams && pb[-1] == 0x00)
{
return (FARPROC)MAKELP(SELECTOROF(pb), OFFSETOF(pb)-5+*(WORD FAR *)(pb-7));
}
Assert(0);
return RealProc;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
#define DCisMem 0x01 // DC is to a memory bitmap
#define DCisDisplay 0x02 // DC is to the screen device
#define DC_DIB 0x80
#define BITMAP_DIB 0x04
#define ChkDispPal 0x0200
BOOL IsValidSaveDC(HGDIOBJ h)
{
HBITMAP hbm;
DIBENGINE FAR * pde;
UINT dcFlags;
if (IsGDIObject(h) != OBJ_DC)
{
DPF("*** invalid SaveDC (%04X)", h);
return FALSE;
}
dcFlags = GetW(h, 0x0E);
if (!(dcFlags & DCisDisplay))
{
DPF("*** SaveDC (%04X) not a display DC", h);
return FALSE;
}
hbm = (HBITMAP)GetW(h, 0x1E);
if (IsGDIObject(hbm) != OBJ_BITMAP)
{
DPF("*** SaveDC (%04X) has invalid bitmap (%04X)", h, hbm);
return FALSE;
}
pde = (DIBENGINE FAR *)MAKELP(GetW(h, 0x32), GetW(h, 0x30));
if (IsBadReadPtr(pde, sizeof(DIBENGINE)))
{
DPF("*** SaveDC (%04X) has bad lpPDevice (%04X:%04X)", h, HIWORD(pde), LOWORD(pde));
return FALSE;
}
if (pde->deType != TYPE_DIBENG)
{
DPF("*** SaveDC (%04X) not a DIBENG PDevice (%04X:%04X)", h, HIWORD(pde), LOWORD(pde));
return FALSE;
}
return TRUE;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
void SaveDCReSelectObjects(HGDIOBJ h, LPARAM lParam)
{
COLORREF rgb;
HDC hdc = (HDC)h;
static HGDIOBJ (WINAPI *ISelectObject)(HDC hdc, HGDIOBJ h);
static COLORREF (WINAPI *ISetTextColor)(HDC hdc, COLORREF rgb);
static COLORREF (WINAPI *ISetBkColor)(HDC hdc, COLORREF rgb);
if (ISelectObject == NULL)
{
(FARPROC)ISelectObject = GetInternalProc((FARPROC)SelectObject, (FARPROC)SetTextColor, 4);
(FARPROC)ISetTextColor = GetInternalProc((FARPROC)SetTextColor, (FARPROC)SetBkColor, 6);
(FARPROC)ISetBkColor = GetInternalProc((FARPROC)SetBkColor, (FARPROC)SetBkMode, 6);
}
if (IsValidSaveDC(h))
{
DPF("ReSelecting objects for SaveDC %04X", h);
ISelectObject(hdc, ISelectObject(hdc, GetStockObject(BLACK_BRUSH)));
ISelectObject(hdc, ISelectObject(hdc, GetStockObject(BLACK_PEN)));
rgb = ISetTextColor(hdc, 0x000000);
ISetTextColor(hdc, 0xFFFFFF);
ISetTextColor(hdc, rgb);
rgb = ISetBkColor(hdc, 0x000000);
ISetBkColor(hdc, 0xFFFFFF);
ISetBkColor(hdc, rgb);
}
}
/*----------------------------------------------------------------------------*\
*
* SaveDCFix
*
* make sure the dcPlanes and dcBitsPixel are patched right in SaveDC blocks.
*
\*----------------------------------------------------------------------------*/
void SaveDCFix(HGDIOBJ h, LPARAM lParam)
{
HBITMAP hbm;
DIBENGINE FAR * pde;
UINT dcFlags;
UINT dcPlanesBitsPixel;
UINT dePlanesBitsPixel;
if (!IsValidSaveDC(h))
{
return;
}
dcPlanesBitsPixel = GetW(h, 0x9C);
dcFlags = GetW(h, 0x0E);
if (dcPlanesBitsPixel == 0x0101)
{
DPF("not Patching dcBitsPixel for SaveDC %04X (mono)", h);
return;
}
if (LOBYTE(dcPlanesBitsPixel) != 1)
{
DPF("not Patching dcBitsPixel for SaveDC %04X (planes!=1)", h);
Assert(0);
return;
}
if (dcFlags & ChkDispPal)
{
DPF("clearing ChkDispPal flag for SaveDC %04X", h);
SetW(h, 0x0E, dcFlags & ~ChkDispPal);
}
if ((dcFlags & DCisMem) && (hbm = (HBITMAP)GetW(h, 0x1E)) != StockBitmap())
{
HDC hdcSel;
HDC hdc;
hdcSel = GetBitmapDC(hbm);
if (hdcSel)
{
DPF("*******************************************");
DPF("*** SaveDC (%04X) has non-stock bitmap. ***", h);
DPF("*******************************************");
hdc = hdcSel;
}
else
{
DPF("**********************************************");
DPF("*** SaveDC (%04X) has non-selected bitmap. ***", h);
DPF("*** restoring bitmap to STOCK bitmap. ***");
DPF("**********************************************");
hdc = CreateCompatibleDC(NULL);
}
//
// copy over the important stuff from the RealDC to the SaveDC
//
if (hdc)
{
PresDC(hdc);
SetW(h, 0x0F, GetW(hdc, 0x0F)); // DCFlags2
SetW(h, 0x26, GetW(hdc, 0x26)); // hPDeviceBlock
SetW(h, 0x38, GetW(hdc, 0x38)); // pPDeviceBlock
SetW(h, 0x22, GetW(hdc, 0x22)); // hLDevice
SetW(h, 0x34, GetW(hdc, 0x34)); // pLDevice
SetW(h, 0x16, GetW(hdc, 0x16)); // hPDevice
SetW(h, 0x30, GetW(hdc, 0x30)); // lpPDevice.off
SetW(h, 0x32, GetW(hdc, 0x32)); // lpPDevice.sel
SetW(h, 0x36, GetW(hdc, 0x36)); // hBitBits
SetW(h, 0x9C, GetW(hdc, 0x9C)); // dcPlanes + dcBitsPixel
}
if (hdc && hdcSel == NULL)
{
DeleteDC(hdc);
}
return;
#if 0 // broken code
SetW(h, 0x30, 0); // lpPDevice.off
SetW(h, 0x32, GetW(hbm, 0x0E)); // lpPDevice.sel
SetW(h, 0x36, GetW(hbm, 0x0E)); // hBitBits
w = GetW(h, 0x0F); // DCFlags2
if (GetW(hbm, 0x1E) & BITMAP_DIB) // bmFlags
w |= DC_DIB;
else
w &= ~DC_DIB;
SetW(h, 0x0F, w); // DCFlags2
#endif
}
pde = (DIBENGINE FAR *)MAKELP(GetW(h, 0x32), GetW(h, 0x30));
Assert(!IsBadReadPtr(pde, sizeof(DIBENGINE)) && pde->deType == TYPE_DIBENG);
dePlanesBitsPixel = *(WORD FAR *)&pde->dePlanes;
if (dePlanesBitsPixel != dcPlanesBitsPixel)
{
DPF("Patching dcBitsPixel for SaveDC %04X %04X=>%04X", h, dcPlanesBitsPixel, dePlanesBitsPixel);
SetW(h,0x9C,dePlanesBitsPixel);
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// END EVIL
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#ifdef DIRECT_DRAW
#undef DPF
#ifdef DEBUG
#define DPF DPF2
static void CDECL DPF2(char *sz, ...)
{
char ach[128];
wvsprintf(ach, sz, (LPVOID)(&sz+1));
#ifdef DIRECT_DRAW
dprintf(2, ach);
#else
lstrcat(ach, "\r\n");
OutputDebugString(ach);
#endif
}
static void CDECL DPF5(char *sz, ...)
{
char ach[128];
wvsprintf(ach, sz, (LPVOID)(&sz+1));
#ifdef DIRECT_DRAW
dprintf(5, ach);
#else
lstrcat(ach, "\r\n");
OutputDebugString(ach);
#endif
}
static void CDECL DPF7(char *sz, ...)
{
char ach[128];
wvsprintf(ach, sz, (LPVOID)(&sz+1));
#ifdef DIRECT_DRAW
dprintf(7, ach);
#else
lstrcat(ach, "\r\n");
OutputDebugString(ach);
#endif
}
#else
#define DPF ; / ## /
#define DPF5 ; / ## /
#define DPF7 ; / ## /
#endif
// Utility for dumping information about ColorTables
#ifdef DEBUG_PAL
void DPF_PALETTE( BITMAPINFO *pbmi )
{
DWORD i;
DWORD *prgb = (DWORD *)(((BYTE *)pbmi)+pbmi->bmiHeader.biSize);
DWORD cEntries = pbmi->bmiHeader.biClrUsed;
if (pbmi->bmiHeader.biBitCount > 8)
return;
if (cEntries == 0)
cEntries = 1 << (pbmi->bmiHeader.biBitCount);
DPF7("Dumping Color table (0xFFRRGGBB) with %d entries", cEntries);
for (i = 0; i < cEntries; i++)
{
DPF7("0x%lx", prgb[i]);
}
}
#else
#define DPF_PALETTE(x)
#endif
// Utility for Dumping information about Bitmap Infos
#ifdef DEBUG_BMI
void DPF_PBMI( BITMAPINFO * pbmi )
{
char *szT;
DPF5("Dumping a BitmapInfo struct");
DPF5("\t\tdeBitmapInfo->bmiHeader.biSize = %ld",pbmi->bmiHeader.biSize);
DPF5("\t\tdeBitmapInfo->bmiHeader.biWidth = %ld",pbmi->bmiHeader.biWidth);
DPF5("\t\tdeBitmapInfo->bmiHeader.biHeight = %ld",pbmi->bmiHeader.biHeight);
DPF5("\t\tdeBitmapInfo->bmiHeader.biPlanes = %d",pbmi->bmiHeader.biPlanes);
DPF5("\t\tdeBitmapInfo->bmiHeader.biBitCount = %d",pbmi->bmiHeader.biBitCount);
szT = ((pbmi->bmiHeader.biCompression == BI_RGB) ? "BI_RGB" : "**UNKNOWN**");
DPF5("\t\tdeBitmapInfo->bmiHeader.biCompression = 0x%lx(%s)",pbmi->bmiHeader.biCompression, szT);
DPF5("\t\tdeBitmapInfo->bmiHeader.biSizeImage = %ld",pbmi->bmiHeader.biSizeImage);
DPF5("\t\tdeBitmapInfo->bmiHeader.biXPelsPerMeter = 0x%lx",pbmi->bmiHeader.biXPelsPerMeter);
DPF5("\t\tdeBitmapInfo->bmiHeader.biYPelsPerMeter = 0x%lx",pbmi->bmiHeader.biYPelsPerMeter);
DPF5("\t\tdeBitmapInfo->bmiHeader.biClrUsed = %ld",pbmi->bmiHeader.biClrUsed);
DPF5("\t\tdeBitmapInfo->bmiHeader.biClrImportant = %ld",pbmi->bmiHeader.biClrImportant);
DPF_PALETTE(pbmi);
}
#else
#define DPF_PBMI(x)
#endif
// Utility for Dumping information about PDEs
#ifdef DEBUG_PDE
void DPF_PDE( DIBENGINE *pde )
{
DPF5("Dumping a DIBENGINE struct.");
DPF5("\tdeType = 0x%x(%s)",pde->deType,(pde->deType == TYPE_DIBENG ? "TYPE_DIBENG" : "**UNKNOWN**"));
DPF5("\tdeWidth = %d",pde->deWidth);
DPF5("\tdeHeight = %d",pde->deHeight);
DPF5("\tdeWidthBytes = %d",pde->deWidthBytes);
DPF5("\tdePlanes = %d",pde->dePlanes);
DPF5("\tdeBitsPixel = %d",pde->deBitsPixel);
DPF5("\tdeReserved1 = 0x%lx",pde->deReserved1);
DPF5("\tdeDeltaScan = %ld",pde->deDeltaScan);
DPF5("\tdelpPDevice = 0x%x",pde->delpPDevice);
DPF5("\tdeBitsOffset = 0x%lx",pde->deBitsOffset);
DPF5("\tdeBitsSelector = 0x%x",pde->deBitsSelector);
DPF5("\tdeFlags = 0x%x(%s)",pde->deFlags,(pde->deFlags == SELECTEDDIB ? "SELECTEDDIB" : "**UNKNOWN**"));
DPF5("\tdeVersion = %d(%s)",pde->deVersion,(pde->deVersion == VER_DIBENG ? "VER_DIBENG" : "**UNKNOWN**"));
DPF5("\tdeBeginAccess = 0x%x",pde->deBeginAccess);
DPF5("\tdeEndAccess = 0x%x",pde->deEndAccess);
DPF5("\tdeDriverReserved = 0x%lx",pde->deDriverReserved);
DPF_PBMI(pde->deBitmapInfo);
}
#else
#define DPF_PDE(x)
#endif
/////////////////////////////////////////////////////////////////////////////
//
// DC stuff
//
/////////////////////////////////////////////////////////////////////////////
DIBENGINE FAR *pdeDisplay;
UINT FlatSel;
static HRGN hVisRgn;
static HDC hdcCache;
static BOOL bCache565;
static int in_use;
static int save_level;
static DWORD cacheBPP;
extern HINSTANCE hInstApp;
extern void FAR PASCAL SelectVisRgn(HDC, HRGN);
extern HDC FAR PASCAL GetDCState(HDC);
extern void FAR PASCAL SetDCState(HDC,HDC);
BOOL DPMISetSelectorLimit(UINT selector, DWORD dwLimit);
extern DWORD PASCAL MapLS( LPVOID ); // flat -> 16:16
extern void PASCAL UnMapLS( DWORD ); // unmap 16:16
/////////////////////////////////////////////////////////////////////////////
//
// SetDC
// NOTE: all calls to SetDC must be matched with SetDC(hdc,0,0,0);
//
/////////////////////////////////////////////////////////////////////////////
BOOL NEAR PASCAL SetDC(HDC hdc, HDC hdcDevice, LPDDSURFACEDESC pddsd, LPPALETTEENTRY lpPalette)
{
DIBENGINE FAR *pde;
int width;
int height;
int bpp;
UINT flags;
DWORD p16Surface;
pde = GetPDevice(hdc);
if (pde == NULL)
return FALSE;
Assert(pde->deType == 0x5250);
Assert(pdeDisplay && pdeDisplay->deType == 0x5250);
if (pddsd == 0)
{
pde->deFlags |= BUSY;
pde->deBitsOffset = 0;
pde->deBitsSelector = 0;
if( pde->deBitmapInfo->bmiHeader.biXPelsPerMeter == 0 )
{
DPF("SetDC NULL called on a DC that was never cooked by DDraw.");
Assert(0);
return TRUE;
}
// This code "should be done" but it causes
// us to SelectVisRgn more often then necessary (and more
// often than we did in DX1-4). This is safer.
// pde->deBitmapInfo->bmiHeader.biWidth = 1;
// pde->deBitmapInfo->bmiHeader.biHeight = -1;
// pde->deBitmapInfo->bmiHeader.biSizeImage = 4;
// We need to unmap the selector we allocated below
Assert(pde->deReserved1 != 0);
UnMapLS(pde->deReserved1);
// Basically, we just want to restore the flags
// to what they were when we got DC originally
DPF5("Restore pde->deReserved1 to 0x%lx", pde->deBitmapInfo->bmiHeader.biXPelsPerMeter);
pde->deReserved1 = pde->deBitmapInfo->bmiHeader.biXPelsPerMeter;
pde->deBitmapInfo->bmiHeader.biXPelsPerMeter = 0;
Assert(pde->deReserved1 != 0);
pde->deBitsSelector = (WORD)((DWORD)pde->deReserved1 >> 16);
return TRUE;
}
// Allocate a selector
p16Surface = MapLS(pddsd->lpSurface);
if( !p16Surface )
{
DPF("Couldn't allocate selector; Out of selectors.");
return FALSE;
}
if( (WORD)p16Surface != 0 )
{
DPF("MapLS didn't return a 16:0 pointer!");
Assert(0);
return FALSE;
}
// Set the selector limit for this chunk of memory
Assert(pddsd->dwHeight > 0);
Assert(pddsd->lPitch > 0);
if( !DPMISetSelectorLimit( (UINT)(p16Surface>>16), (pddsd->dwHeight*pddsd->lPitch) - 1 ) )
{
DPF("Couldn't update selector; Out of selectors.");
UnMapLS(p16Surface);
return FALSE;
}
DPF5("SetDC: Details of PDE from initial hdc.");
DPF_PDE(pde);
width = (int)pddsd->dwWidth,
height = (int)pddsd->dwHeight,
bpp = (int)pddsd->ddpfPixelFormat.dwRGBBitCount,
flags = (UINT)pddsd->ddpfPixelFormat.dwRBitMask == 0xf800 ? FIVE6FIVE : 0;
pde->deFlags &= ~BUSY;
// Also, make sure we set all if any banked bits are set in the driver
// to encourage the DIBENG to avoid screen to screen blts (which are apparently buggy).
// Only do this for BankSwitched VRAM surfaces.
// ATTENTION: MULTIMON pdeDisplay is the primary; we should check
// the hdcDevice instead
if ((pddsd->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) &&
(pdeDisplay->deFlags & (NON64KBANK|BANKEDVRAM|BANKEDSCAN)))
{
pde->deFlags |= (NON64KBANK|BANKEDVRAM|BANKEDSCAN);
}
else
{
pde->deFlags &= ~(NON64KBANK|BANKEDVRAM|BANKEDSCAN);
}
pde->deDeltaScan = (DWORD)pddsd->lPitch;
pde->deWidthBytes = (WORD)pddsd->lPitch;
// We use the selector we just allocated instead of the
// flatsel + offset because it is a little safer if
// something bad happens and someone goes off the end.
pde->deBitsOffset = 0;
pde->deBitsSelector = (WORD)(p16Surface >> 16);
pde->deBitmapInfo->bmiHeader.biXPelsPerMeter = pde->deReserved1;
pde->deReserved1 = (DWORD)p16Surface;
//
// for a 8bit surface we want to color table to be the same as the
// display (so it acts like a DDB not a DIB)
//
// For non-8bit surfaces; we don't need to do anything w.r.t. color table.
//
if (bpp == 8)
{
DWORD FAR *pdw;
int i;
RGBQUAD rgbT = {0,0,0,0};
// Use our palette if it is explicitly set on the surface
if (lpPalette)
{
DPF( "Need a DC for an 8 bit surface with palette" );
Assert(pde->deBitmapInfo->bmiHeader.biBitCount == (DWORD)bpp);
// We use Pitch instead of Width because the "pitch" of
// dibsection is assumed to be the width rounded up to the next
// DWORD
pde->deBitmapInfo->bmiHeader.biWidth = (DWORD)pddsd->lPitch;
pde->deBitmapInfo->bmiHeader.biHeight = -height; // negative height for top-down DIB
pde->deBitmapInfo->bmiHeader.biSizeImage = 0;
pde->deBitmapInfo->bmiHeader.biClrImportant = 256;
// We call this because it sets a magic number which
// has the effect of resetting any cached color translation
// tables that GDI may have set up for us.
SetDIBColorTable(hdc, 0, 1, &rgbT);
pdw = (DWORD FAR *)pde->deBitmapInfo;
pdw = (DWORD FAR *)((BYTE FAR *)pdw + pdw[0]); // + biSize
for (i=0; i<256; i++)
pdw[i] = RGB(lpPalette[i].peBlue,lpPalette[i].peGreen,lpPalette[i].peRed);
}
else
{
DWORD FAR *pdwSrc;
DIBENGINE FAR *pdeDevice;
if (hdcDevice)
pdeDevice = GetPDevice(hdcDevice);
else
pdeDevice = pdeDisplay;
// This needs to be checked sooner.
Assert(pdeDevice && pdeDevice->deType == 0x5250);
Assert(pdeDevice->deBitsPixel == 8);
// In DX5, we will just modify our own bitmap info
// by copying the colors from the primary. In DX3, we
// pointed out bitmap info to the primary's; but that
// relies on the potentially bad assumption that our bitmap
// info will have a shorter life span to the primary's mode.
//
// It also doesn't work because the biWidth/biHeight fields
// of the device's primary don't match our own width/height
//
pdwSrc = (DWORD FAR *)(pdeDevice->deBitmapInfo);
pdwSrc = (DWORD FAR *)((BYTE FAR *)pdwSrc + pdwSrc[0]); // + biSize
pdw = (DWORD FAR *)pde->deBitmapInfo;
pdw = (DWORD FAR *)((BYTE FAR *)pdw + pdw[0]); // + biSize
// We call this because it sets a magic number which
// has the effect of resetting any cached color translation
// tables that GDI may have set up for us.
SetDIBColorTable(hdc, 0, 1, &rgbT);
// Copy all the colors to our color table
// We also clear all the special flags in our copy
for (i=0; i<256; i++)
pdw[i] = (pdwSrc[i] & 0x00FFFFFF);
// Fixup the rest of the bitmapinfo
// We use Pitch instead of Width because the "pitch" of
// dibsection is assumed to be the width rounded up to the next
// DWORD
pde->deBitmapInfo->bmiHeader.biWidth = (DWORD)pddsd->lPitch;
pde->deBitmapInfo->bmiHeader.biHeight = -height; // negative height for top-down DIB
pde->deBitmapInfo->bmiHeader.biSizeImage = 0;
pde->deBitmapInfo->bmiHeader.biClrImportant = 256;
}
}
else
{
// We need to convert Pitch into the number of whole
// pixels per scanline. There may be round-down errors
// however, since GDI assumes that Pitches must be multiples
// of 4; they round-up.
DWORD pitch = (DWORD)pddsd->lPitch;
if (bpp == 16)
pitch = pitch / 2;
else if (bpp == 24)
pitch = pitch / 3;
else if (bpp == 32)
pitch = pitch / 4;
else if (bpp == 4)
pitch = pitch * 2;
else if (bpp == 2)
pitch = pitch * 4;
else if (bpp == 1)
pitch = pitch * 8;
else
Assert(0); // unexpected bpp
pde->deBitmapInfo->bmiHeader.biWidth = pitch;
pde->deBitmapInfo->bmiHeader.biHeight = -height; // negative height for top-down DIB
pde->deBitmapInfo->bmiHeader.biSizeImage = 0;
Assert(pde->deBitmapInfo->bmiHeader.biBitCount == (DWORD)bpp);
}
//
// if the width/height of the dc has changed we need to set
// a new vis region
//
if (width != (int)pde->deWidth || height != (int)pde->deHeight)
{
pde->deWidth = width;
pde->deHeight = height;
SetRectRgn(hVisRgn, 0, 0, width, height);
SelectVisRgn(hdc, hVisRgn);
}
//
// when the bpp changes dont forget to fix up the deFlags
// and ReSelect all the objects so they match the new bitdepth
//
if (pde->deBitsPixel != bpp || ((pde->deFlags ^ flags) & FIVE6FIVE))
{
if (flags & FIVE6FIVE)
pde->deFlags |= FIVE6FIVE;
else
pde->deFlags &= ~FIVE6FIVE;
pde->deBitsPixel = bpp;
ReSelectObjects(hdc, 0);
}
DPF5("SetDC: Details of PDE returned.");
DPF_PDE(pde);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
// AllocFlatSel
//
/////////////////////////////////////////////////////////////////////////////
#pragma optimize("", off)
UINT NEAR PASCAL AllocFlatSel()
{
if (FlatSel != 0)
return FlatSel;
FlatSel = AllocSelector(SELECTOROF((LPVOID)&FlatSel));
if (FlatSel == 0)
return 0;
SetSelectorBase(FlatSel, 0);
// SetSelectorLimit(FlatSel, -1);
_asm mov ax,0008h ; DPMI set limit
_asm mov bx,FlatSel
_asm mov dx,-1
_asm mov cx,-1
_asm int 31h
return FlatSel;
}
BOOL DPMISetSelectorLimit(UINT selector, DWORD dwLimit)
{
BOOL bRetVal=TRUE;
// If the limit is >= 1MB, we need to make the limit a mulitple
// of the page size or DPMISetSelectorLimit will fail.
if( dwLimit >= 0x100000 )
dwLimit |= 0x0FFF;
__asm
{
mov ax, 0008h
mov bx, selector
mov cx, word ptr [dwLimit+2]
mov dx, word ptr [dwLimit]
int 31h
jnc success
mov bRetVal, FALSE
success:
}
return bRetVal;
}
#pragma optimize("", on)
/////////////////////////////////////////////////////////////////////////////
//
// InitDC
//
/////////////////////////////////////////////////////////////////////////////
BOOL NEAR PASCAL InitDC(void)
{
HDC hdc;
UINT rc;
DIBENGINE FAR *pde;
if (pdeDisplay != NULL)
{
return TRUE;
}
//
// get the PDevice of the display we are going to need to copy
// some info
//
if (pdeDisplay == NULL)
{
hdc = GetDC(NULL);
rc = GetDeviceCaps(hdc, CAPS1);
pde = GetPDevice(hdc);
ReleaseDC(NULL, hdc);
if (!(rc & C1_DIBENGINE) ||
IsBadReadPtr(pde, 2) || pde->deType != 0x5250 ||
GetProfileInt("DirectDraw", "DisableGetDC", 0))
{
DPF("DD16_GetDC: GetDC is disabled");
return FALSE;
}
pdeDisplay = pde;
}
if (FlatSel == 0)
{
AllocFlatSel();
}
if (hVisRgn == NULL)
{
hVisRgn = CreateRectRgn(0,0,0,0);
SetObjectOwner(hVisRgn, hInstApp);
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
// MakeDC
//
/////////////////////////////////////////////////////////////////////////////
HDC NEAR PASCAL MakeDC(DWORD bpp, BOOL f565)
{
HDC hdc;
HBITMAP hbm;
DIBENGINE FAR *pde;
DIB8 BitmapInfo = {sizeof(BITMAPINFOHEADER), 1, -1, 1, 8, BI_RGB, 0, 0, 0, 0, 0};
if (pdeDisplay == NULL)
return NULL;
hdc = GetDC(NULL);
if (bpp == 8)
{
BitmapInfo.ct[0] = RGB(0,0,0);
BitmapInfo.ct[255] = RGB(255, 255, 255);
}
else if (bpp == 16)
{
if (f565)
{
BitmapInfo.bi.biCompression = BI_BITFIELDS;
BitmapInfo.ct[0] = 0xf800;
BitmapInfo.ct[1] = 0x07e0;
BitmapInfo.ct[2] = 0x001f;
}
}
BitmapInfo.bi.biBitCount = (UINT)bpp;
hbm = CreateDIBSection(hdc, (BITMAPINFO FAR *)&BitmapInfo, DIB_RGB_COLORS, NULL, NULL, 0);
ReleaseDC(NULL, hdc);
if (hbm == NULL)
return NULL;
hdc = CreateCompatibleDC(NULL);
SelectObject(hdc, hbm);
pde = GetPDevice(hdc);
if (IsBadReadPtr(pde, 2) || pde->deType != 0x5250)
{
DeleteDC(hdc);
DeleteObject(hbm);
return NULL;
}
//
// ok we have the following:
//
// pde --> DIBSECTION (DIBENGINE)
// pdeDisplay --> DISPLAY PDevice (DIBENGINE)
//
// make the DIBSECTION be compatible with the display
// set the following fields from the DISPLAY PDevice:
//
// deBitsPixel
// deFlags (FIVE6FIVE, PALETTIZED, MINIDRIVER, ...)
// deBitmapInfo
//
pde->deBeginAccess = 0;
pde->deEndAccess = 0;
// deDriverReserved has three states
// 0 - Do Not Cache a translation table
// 1 - Translation table is same as Screen
// >1 - Unique ID indicating state of palette (to indicate when cached translation table is out of date)
//
// For 24 and 32bpp, it never makes sense to cache a translation table
// because no translation table is built for our surface as the destination.
// Win95 Gold DIBEngine has a bug which screws up when doing 8-to-24/32 blts
// because it incorrectly tries to cache the table. So we set deDriverReserved
// to 0 for 24/32 bpp.
//
// We have been setting deDriverReserved to 1; but we probably should not
// be doing this anymore; we should be leaving it alone which means
// that it gets the unique number given to each dibsection.
//
if (bpp == 16 || bpp == 24 || bpp == 32)
pde->deDriverReserved = 0;
else
pde->deDriverReserved = 1; // ID for the screen
pde->deBitsPixel = 0; // set SetDC will see it has changed
// pde->deFlags = pdeDisplay->deFlags;
// pde->deFlags &= ~(VRAM|NOT_FRAMEBUFFER|NON64KBANK|BANKEDVRAM|BANKEDSCAN|PALETTE_XLAT);
// pde->deFlags |= OFFSCREEN;
// pde->deFlags |= MINIDRIVER; need to clear SELECTEDDIB
// if the main display is banked, make the DCs banked because they
//may be used for video memory
//
// ATTENTION we should only do this for video memory
// surfaces not memory surfaces. move this code to SetDC
// Also, make sure we set all if any banked bits are set in the driver
// to encourage the DIBENG to avoid screen to screen blts (which are apparently buggy).
//
if(pdeDisplay->deFlags & (NON64KBANK|BANKEDVRAM|BANKEDSCAN))
{
pde->deFlags |= (NON64KBANK|BANKEDVRAM|BANKEDSCAN);
}
// This bit should only ever be used in conjunction with VRAM
// setting it can confuses drivers (such as the 765) into thinking that
// the surface is in VRAM when it is not.
// pde->deFlags |= OFFSCREEN;
pde->deFlags |= BUSY;
SetObjectOwner(hdc, hInstApp);
SetObjectOwner(hbm, hInstApp);
return hdc;
}
/////////////////////////////////////////////////////////////////////////////
//
// FreeDC
//
/////////////////////////////////////////////////////////////////////////////
BOOL NEAR PASCAL FreeDC(HDC hdc)
{
if (hdc)
{
HBITMAP hbm;
hbm = SelectObject(hdc, StockBitmap());
DeleteDC(hdc);
DeleteObject(hbm);
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
// DD16_MakeObjectPrivate
// This function makes sure that no DC that we need is
// freed until we want it to be freed.
//
/////////////////////////////////////////////////////////////////////////////
WORD DDAPI DD16_MakeObjectPrivate(HDC hdc, BOOL fPrivate)
{
BOOL fState;
// Assert that parameter is good
Assert(IsGDIObject(hdc) == OBJ_DC);
fState = MakeObjectPrivate(hdc, fPrivate);
if (fState)
{
return 1;
}
else
{
return 0;
}
}
/////////////////////////////////////////////////////////////////////////////
//
// DD16_GetDC
//
/////////////////////////////////////////////////////////////////////////////
HDC DDAPI DD16_GetDC(HDC hdcDevice, LPDDSURFACEDESC pddsd, LPPALETTEENTRY lpPalette)
{
HDC hdc;
BOOL f565;
// Assert that parameter is good
Assert(IsGDIObject(hdcDevice) == OBJ_DC);
// must be a RGB format surface!
//
if (!(pddsd->ddpfPixelFormat.dwFlags & DDPF_RGB))
{
DPF("DD16_GetDC: must be a RGB surface");
return NULL;
}
//
// if the surface is 8bpp the display must also be 8bpp because we
// share the color table. (Multi-mon: make sure we check the right display.)
//
// If a palette is explicitly passed in, then we won't need
// the device's pde.
//
if( pddsd->ddpfPixelFormat.dwRGBBitCount == 8 && lpPalette == NULL )
{
DIBENGINE FAR *pdeDevice;
if( hdcDevice )
pdeDevice = GetPDevice( hdcDevice );
else
pdeDevice = pdeDisplay;
// 3DFx isn't a real device DC
if (pdeDevice->deType != 0x5250)
{
DPF("Can't get DC on an 8bpp surface without a palette for this device");
return NULL;
}
if (pdeDevice->deBitsPixel != 8 )
{
DPF("Can't get DC on an 8bpp surface without a palette when primary is not at 8bpp");
return NULL;
}
}
#ifdef DEBUG
//
// we assume the pixel format is not wacky
//
if (pddsd->ddpfPixelFormat.dwRGBBitCount == 8 )
{
/*
* The Permedia driver actually reports bit masks for their 8bit palettized mode, so
* we shouldn't assert here (as we used to) if any masks are non-zero.
*/
if ( ( pddsd->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) ==0 )
{
DPF("Getting a DC on a non-palettized 8bit surface!");
Assert(0);
}
}
else if ( pddsd->ddpfPixelFormat.dwRGBBitCount == 4 ||
pddsd->ddpfPixelFormat.dwRGBBitCount == 1)
{
/*
* Assume these are OK
*/
}
else if (pddsd->ddpfPixelFormat.dwRGBBitCount == 16)
{
if (pddsd->ddpfPixelFormat.dwRBitMask == 0xf800 &&
pddsd->ddpfPixelFormat.dwGBitMask == 0x07e0 &&
pddsd->ddpfPixelFormat.dwBBitMask == 0x001f)
{
// 565
}
else if (
pddsd->ddpfPixelFormat.dwRBitMask == 0x7c00 &&
pddsd->ddpfPixelFormat.dwGBitMask == 0x03e0 &&
pddsd->ddpfPixelFormat.dwBBitMask == 0x001f)
{
// 555
}
else
{
DPF("DD16_GetDC: not 555 or 565");
Assert(0);
}
}
else if (pddsd->ddpfPixelFormat.dwRGBBitCount == 24 )
{
if (pddsd->ddpfPixelFormat.dwBBitMask == 0x0000FF &&
pddsd->ddpfPixelFormat.dwGBitMask == 0x00FF00 &&
pddsd->ddpfPixelFormat.dwRBitMask == 0xFF0000)
{
// 888 BGR
}
else
{
DPF("DD16_GetDC: invalid bit masks");
Assert(0);
}
}
else if(pddsd->ddpfPixelFormat.dwRGBBitCount == 32)
{
if (pddsd->ddpfPixelFormat.dwRBitMask == 0xFF0000 &&
pddsd->ddpfPixelFormat.dwGBitMask == 0x00FF00 &&
pddsd->ddpfPixelFormat.dwBBitMask == 0x0000FF)
{
// 888 RGB -- standard 32-bit format
}
else
{
DPF("DD16_GetDC: invalid bit masks");
Assert(0);
}
}
else
{
DPF("DD16_GetDC: invalid bit depth");
Assert(0);
}
#endif
// is this a 565?
f565 = FALSE;
if (pddsd->ddpfPixelFormat.dwRGBBitCount == 16 &&
pddsd->ddpfPixelFormat.dwRBitMask == 0xf800)
f565 = TRUE;
//
// use the cacheDC if it is free, else make a new one.
//
if( in_use || ( pddsd->ddsCaps.dwCaps & DDSCAPS_OWNDC ) )
{
hdc = MakeDC( pddsd->ddpfPixelFormat.dwRGBBitCount, f565 );
}
else
{
if (cacheBPP != pddsd->ddpfPixelFormat.dwRGBBitCount || bCache565 != f565 )
{
FreeDC(hdcCache);
hdcCache = MakeDC(pddsd->ddpfPixelFormat.dwRGBBitCount, f565);
cacheBPP = pddsd->ddpfPixelFormat.dwRGBBitCount;
bCache565 = f565;
}
hdc = hdcCache;
in_use++;
}
//
// now set the right bits pointer.
//
if (hdc)
{
BOOL fSuccess;
// Set the DC with the right information based
// on the surface. If a palette is passed in
// then set that palette into the DC.
fSuccess = SetDC(hdc, hdcDevice, pddsd, lpPalette);
if( !fSuccess )
{
DPF("SetDC Failed");
// We need to clean up; but we
// can't call ReleaseDC because our dc is only
// half-cooked.
if (hdc == hdcCache)
{
Assert(in_use == 1);
in_use = 0;
}
else
{
FreeDC(hdc);
}
return NULL;
}
}
if (hdc && hdc == hdcCache)
{
save_level = SaveDC(hdc);
}
return hdc;
}
/////////////////////////////////////////////////////////////////////////////
//
// DD16_ReleaseDC
//
/////////////////////////////////////////////////////////////////////////////
void DDAPI DD16_ReleaseDC(HDC hdc)
{
if (hdc == NULL)
return;
if (hdc == hdcCache)
{
RestoreDC(hdc, save_level);
SetDC(hdc, NULL, NULL, NULL);
Assert(in_use == 1);
in_use = 0;
}
else
{
SetDC(hdc, NULL, NULL, NULL);
FreeDC(hdc);
}
}
/////////////////////////////////////////////////////////////////////////////
//
// DD16_SafeMode
//
// dynamic safe mode
//
/////////////////////////////////////////////////////////////////////////////
BOOL DDAPI DD16_SafeMode(HDC hdc, BOOL fSafeMode)
{
extern void PatchDisplay(int oem, BOOL patch); // dynares.c
int i;
for (i=0; i<35; i++)
{
PatchDisplay(i, fSafeMode);
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
// DD16_Exclude
// DD16_Unexclude
//
// call the exclude or unexclude callbacks in the display driver
//
/////////////////////////////////////////////////////////////////////////////
typedef void (FAR PASCAL *BEGINACCESSPROC)(LPVOID lpPDevice, int left, int top, int right, int bottom, WORD flags);
typedef void (FAR PASCAL *ENDACCESSPROC)(LPVOID lpPDevice, WORD flags);
void DDAPI DD16_Exclude(DWORD dwPDevice, RECTL FAR *prcl)
{
DIBENGINE FAR *pde = (DIBENGINE FAR *)dwPDevice;
Assert(pde && pde->deType == 0x5250);
Assert(prcl != NULL);
Assert(pde->deFlags & BUSY);
if (pde->deBeginAccess)
{
BEGINACCESSPROC OEMBeginAccess = (BEGINACCESSPROC)pde->deBeginAccess;
//
// when DirectDraw calls us it has already taken the BUSY bit
// but BUSY needs to be clear for the cursor to be excluded.
// so release the BUSY bit while we call the driver, this is
// a ok thing to do because we have the Win16Lock.
//
pde->deFlags &= ~BUSY;
OEMBeginAccess(pde, (int)prcl->left, (int)prcl->top,
(int)prcl->right, (int)prcl->bottom, CURSOREXCLUDE);
pde->deFlags |= BUSY;
}
}
void DDAPI DD16_Unexclude(DWORD dwPDevice)
{
DIBENGINE FAR *pde = (DIBENGINE FAR *)dwPDevice;
Assert(pde && pde->deType == 0x5250);
if (pde->deEndAccess)
{
ENDACCESSPROC OEMEndAccess = (ENDACCESSPROC)pde->deEndAccess;
OEMEndAccess(pde, CURSOREXCLUDE);
}
}
/*
* DD16_AttemptGamma
*
* Total HACK! The GetDeviceGammaRamp call can attempt to call a NULL
* entry. Since we can't fix Win95, instead we look at the entry that
* it will call and suggest that they don't call it if it's NULL.
*/
BOOL DDAPI DD16_AttemptGamma( HDC hdc )
{
WORD wLDevice;
WORD FAR *pw;
UINT hGDI = GetGdiDS();
wLDevice = GetW(hdc, 0x34);
if( wLDevice != 0 )
{
pw = MAKELP(hGDI, wLDevice);
if (!IsBadReadPtr(pw, 0x80))
{
pw = MAKELP(hGDI, wLDevice + 0x7C);
if (*pw != NULL)
{
return TRUE;
}
}
}
return FALSE;
} /* DD16_AttemptGamma */
/*
* DD16_IsDeviceBusy
*
* Determines if the device represented by the HDC is
* busy or not.
*/
BOOL DDAPI DD16_IsDeviceBusy( HDC hdc )
{
DIBENGINE FAR *pde;
pde = GetPDevice(hdc);
if(pde == NULL)
return FALSE;
Assert(pde->deType==0x5250);
return pde->deFlags & BUSY;
} /* DD16_IsDeviceBusy */
/////////////////////////////////////////////////////////////////////////////
//
// DD16_Stretch
//
// call the DIBENG to do a stretch.
//
/////////////////////////////////////////////////////////////////////////////
extern int FAR PASCAL DIB_Stretch(
DIBENGINE FAR *dst, int, int, int, int,
DIBENGINE FAR *src, int, int, int, int,
DWORD Rop, LPVOID lpPBrush, LPVOID lpDrawMode, LPRECT lpClip);
extern int FAR PASCAL DIB_BitBlt(
DIBENGINE FAR *dst, int xD, int yD,
DIBENGINE FAR *src, int xS, int yS, int w, int h,
DWORD Rop, LPVOID lpPBrush, LPVOID lpDrawMode);
typedef struct {
short int Rop2;
short int bkMode;
unsigned long int bkColor;
unsigned long int TextColor;
short int TBreakExtra;
short int BreakExtra;
short int BreakErr;
short int BreakRem;
short int BreakCount;
short int CharExtra;
unsigned long int LbkColor;
unsigned long int LTextColor;
DWORD ICMCXform;
short StretchBltMode;
DWORD eMiterLimit;
} DRAWMODE;
int DDAPI DD16_Stretch(DWORD DstPtr, int DstPitch, UINT DstBPP, int DstX, int DstY, int DstDX, int DstDY,
DWORD SrcPtr, int SrcPitch, UINT SrcBPP, int SrcX, int SrcY, int SrcDX, int SrcDY)//, long Rop3)
{
DIBENGINE src;
DIBENGINE dst;
DRAWMODE dm;
RECT rc;
static DIB8 bmiStretch = {sizeof(BITMAPINFOHEADER), 1, -1, 1, 8, BI_RGB, 0, 0, 0, 0, 0};
//
// make sure we have a flat sel
//
if (FlatSel == 0)
return -1;
// Set the bitdepth on the bitmapinfo
Assert( DstBPP == SrcBPP );
bmiStretch.bi.biBitCount = DstBPP;
//
// setup source DIBENG
//
if (SrcPtr)
{
src.deType = TYPE_DIBENG;
src.deWidth = 10000;
src.deHeight = 10000;
src.deWidthBytes = SrcPitch;
src.dePlanes = 1;
src.deBitsPixel = SrcBPP;
src.deReserved1 = 0;
src.deDeltaScan = SrcPitch;
src.delpPDevice = NULL;
src.deBitsOffset = SrcPtr;
src.deBitsSelector = FlatSel;
src.deFlags = SELECTEDDIB;
src.deVersion = VER_DIBENG;
src.deBitmapInfo = (BITMAPINFO *)&bmiStretch;
src.deBeginAccess = 0;
src.deEndAccess = 0;
src.deDriverReserved= 0;
}
//
// setup dest DIBENG
//
dst.deType = TYPE_DIBENG;
dst.deWidth = 10000;
dst.deHeight = 10000;
dst.deWidthBytes = DstPitch;
dst.dePlanes = 1;
dst.deBitsPixel = DstBPP;
dst.deReserved1 = 0;
dst.deDeltaScan = DstPitch;
dst.delpPDevice = NULL;
dst.deBitsOffset = DstPtr;
dst.deBitsSelector = FlatSel;
dst.deFlags = SELECTEDDIB;
dst.deVersion = VER_DIBENG;
dst.deBitmapInfo = (BITMAPINFO *)&bmiStretch;
dst.deBeginAccess = 0;
dst.deEndAccess = 0;
dst.deDriverReserved = 0;
//
// this memory *might* be in VRAM so setup things to
// work right.
//
// ATTENTION we should only do this for video memory
// surfaces not memory surfaces.
// If any are set, set all the bits to force the DIBENG to
// not do a screen to screen blit (which apparently has a bug).
//
if (pdeDisplay && (pdeDisplay->deFlags & (NON64KBANK|BANKEDVRAM|BANKEDSCAN)))
{
dst.deFlags |= (NON64KBANK|BANKEDVRAM|BANKEDSCAN);
src.deFlags |= (NON64KBANK|BANKEDVRAM|BANKEDSCAN);
}
//
// now call the DIBENG
//
if(SrcPtr == (DWORD)NULL)
{
DPF("Blitting from Primary with HDC unsupported!");
return FALSE;
}
else if ((DstDX == SrcDX) && (DstDY == SrcDY))
{
//DPF("Calling DIB_BitBlt");
// NOTE: If the source and destination video memory pointers
// are the same then we simply pass the destination
// DIBENG for the source as this is how the blt code spots
// the fact that the source and destination surfaces are
// the same and so takes the necessary action to handle
// overlapping surfaces
#ifdef DEBUG
if( DstPtr == SrcPtr)
{
Assert(DstPitch == SrcPitch);
Assert(DstBPP == SrcBPP);
}
#endif
return DIB_BitBlt(&dst, DstX, DstY,
(DstPtr == SrcPtr) ? &dst : &src,
SrcX, SrcY, SrcDX, SrcDY, SRCCOPY, // Rop3,
NULL, &dm);
}
else
{
rc.left = DstX;
rc.top = DstY;
rc.right = DstX + DstDX;
rc.bottom = DstY + DstDY;
dm.StretchBltMode = STRETCH_DELETESCANS;
/* DPF("Calling DIB_StretchBlt with:");
DPF("\tdst.deType = 0x%x(%s)",dst.deType,(dst.deType == TYPE_DIBENG ? "TYPE_DIBENG" : "**UNKNOWN**"));
DPF("\tdst.deWidth = %d",dst.deWidth);
DPF("\tdst.deHeight = %d",dst.deHeight);
DPF("\tdst.deWidthBytes = %d",dst.deWidthBytes);
DPF("\tdst.dePlanes = %d",dst.dePlanes);
DPF("\tdst.deBitsPixel = %d",dst.deBitsPixel);
DPF("\tdst.deReserved1 = %ld",dst.deReserved1);
DPF("\tdst.deDeltaScan = %ld",dst.deDeltaScan);
DPF("\tdst.delpPDevice = 0x%x",dst.delpPDevice);
DPF("\tdst.deBitsOffset = 0x%x",dst.deBitsOffset);
DPF("\tdst.deBitsSelector = 0x%x",dst.deBitsSelector);
DPF("\tdst.deFlags = 0x%x(%s)",dst.deFlags,(dst.deFlags == SELECTEDDIB ? "SELECTEDDIB" : "**UNKNOWN**"));
DPF("\tdst.deVersion = %d(%s)",dst.deVersion,(dst.deVersion == VER_DIBENG ? "VER_DIBENG" : "**UNKNOWN**"));
DPF("\t\tdst.deBitmapInfo->bmiHeader.biSize = %ld",dst.deBitmapInfo->bmiHeader.biSize);
DPF("\t\tdst.deBitmapInfo->bmiHeader.biWidth = %ld",dst.deBitmapInfo->bmiHeader.biWidth);
DPF("\t\tdst.deBitmapInfo->bmiHeader.biHeight = %ld",dst.deBitmapInfo->bmiHeader.biHeight);
DPF("\t\tdst.deBitmapInfo->bmiHeader.biPlanes = %d",dst.deBitmapInfo->bmiHeader.biPlanes);
DPF("\t\tdst.deBitmapInfo->bmiHeader.biBitCount = %d",dst.deBitmapInfo->bmiHeader.biBitCount);
DPF("\t\tdst.deBitmapInfo->bmiHeader.biCompression = 0x%x(%s)",dst.deBitmapInfo->bmiHeader.biCompression,((dst.deBitmapInfo->bmiHeader.biCompression == BI_RGB) ? "BI_RGB" : "**UNKNOWN**"));
DPF("\t\tdst.deBitmapInfo->bmiHeader.biSizeImage = %ld",dst.deBitmapInfo->bmiHeader.biSizeImage);
DPF("\t\tdst.deBitmapInfo->bmiHeader.biXPelsPerMeter = %ld",dst.deBitmapInfo->bmiHeader.biXPelsPerMeter);
DPF("\t\tdst.deBitmapInfo->bmiHeader.biYPelsPerMeter = %ld",dst.deBitmapInfo->bmiHeader.biYPelsPerMeter);
DPF("\t\tdst.deBitmapInfo->bmiHeader.biClrUsed = %ld",dst.deBitmapInfo->bmiHeader.biClrUsed);
DPF("\t\tdst.deBitmapInfo->bmiHeader.biClrImportant = %ld",dst.deBitmapInfo->bmiHeader.biClrImportant);
DPF("\tdst.deBeginAccess = 0x%x",dst.deBeginAccess);
DPF("\tdst.deEndAccess = 0x%x",dst.deEndAccess);
DPF("\tdst.deDriverReserved = 0x%x",dst.deDriverReserved);
DPF("");
DPF("\tDstX = %d",DstX);
DPF("\tDstY = %d",DstY);
DPF("\tDstDX = %d",DstDX);
DPF("\tDstDY = %d",DstDY);
DPF("");
DPF("\tsrc.deType = 0x%x(%s)",src.deType,(src.deType == TYPE_DIBENG ? "TYPE_DIBENG" : "**UNKNOWN**"));
DPF("\tsrc.deWidth = %d",src.deWidth);
DPF("\tsrc.deHeight = %d",src.deHeight);
DPF("\tsrc.deWidthBytes = %d",src.deWidthBytes);
DPF("\tsrc.dePlanes = %d",src.dePlanes);
DPF("\tsrc.deBitsPixel = %d",src.deBitsPixel);
DPF("\tsrc.deReserved1 = %ld",src.deReserved1);
DPF("\tsrc.deDeltaScan = %ld",src.deDeltaScan);
DPF("\tsrc.delpPDevice = 0x%x",src.delpPDevice);
DPF("\tsrc.deBitsOffset = 0x%x",src.deBitsOffset);
DPF("\tsrc.deBitsSelector = 0x%x",src.deBitsSelector);
DPF("\tsrc.deFlags = 0x%x(%s)",src.deFlags,(src.deFlags == SELECTEDDIB ? "SELECTEDDIB" : "**UNKNOWN**"));
DPF("\tsrc.deVersion = %d(%s)",src.deVersion,(src.deVersion == VER_DIBENG ? "VER_DIBENG" : "**UNKNOWN**"));
DPF("\t\tsrc.deBitmapInfo->bmiHeader.biSize = %ld",src.deBitmapInfo->bmiHeader.biSize);
DPF("\t\tsrc.deBitmapInfo->bmiHeader.biWidth = %ld",src.deBitmapInfo->bmiHeader.biWidth);
DPF("\t\tsrc.deBitmapInfo->bmiHeader.biHeight = %ld",src.deBitmapInfo->bmiHeader.biHeight);
DPF("\t\tsrc.deBitmapInfo->bmiHeader.biPlanes = %d",src.deBitmapInfo->bmiHeader.biPlanes);
DPF("\t\tsrc.deBitmapInfo->bmiHeader.biBitCount = %d",src.deBitmapInfo->bmiHeader.biBitCount);
DPF("\t\tsrc.deBitmapInfo->bmiHeader.biCompression = 0x%x(%s)",src.deBitmapInfo->bmiHeader.biCompression,((src.deBitmapInfo->bmiHeader.biCompression == BI_RGB) ? "BI_RGB" : "**UNKNOWN**"));
DPF("\t\tsrc.deBitmapInfo->bmiHeader.biSizeImage = %ld",src.deBitmapInfo->bmiHeader.biSizeImage);
DPF("\t\tsrc.deBitmapInfo->bmiHeader.biXPelsPerMeter = %ld",src.deBitmapInfo->bmiHeader.biXPelsPerMeter);
DPF("\t\tsrc.deBitmapInfo->bmiHeader.biYPelsPerMeter = %ld",src.deBitmapInfo->bmiHeader.biYPelsPerMeter);
DPF("\t\tsrc.deBitmapInfo->bmiHeader.biClrUsed = %ld",src.deBitmapInfo->bmiHeader.biClrUsed);
DPF("\t\tsrc.deBitmapInfo->bmiHeader.biClrImportant = %ld",src.deBitmapInfo->bmiHeader.biClrImportant);
DPF("\tsrc.deBeginAccess = 0x%x",src.deBeginAccess);
DPF("\tsrc.deEndAccess = 0x%x",src.deEndAccess);
DPF("\tsrc.deDriverReserved = 0x%x",src.deDriverReserved);
DPF("");
DPF("\tSrcX = %d",SrcX);
DPF("\tSrcY = %d",SrcY);
DPF("\tSrcDX = %d",SrcDX);
DPF("\tSrcDY = %d",SrcDY);
DPF("");
DPF("\tdm.StretchBltMode = STRETCH_DELETESCANS");
DPF("");
DPF("\trc.left = %d",rc.left);
DPF("\trc.top = %d",rc.top);
DPF("\trc.right = %d",rc.right);
DPF("\trc.bottom = %d",rc.bottom);
DPF("");
*/
return DIB_Stretch(&dst, DstX, DstY, DstDX, DstDY,
&src, SrcX, SrcY, SrcDX, SrcDY, SRCCOPY, // Rop3,
NULL, &dm, &rc);
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void GdiHelpCleanUp()
{
if (FlatSel)
{
SetSelectorLimit(FlatSel, 0);
FreeSelector(FlatSel);
FlatSel = 0;
}
if (hdcCache)
{
FreeDC(hdcCache);
hdcCache = NULL;
}
if (hVisRgn)
{
DeleteObject(hVisRgn);
hVisRgn = NULL;
}
if (pdeDisplay)
{
pdeDisplay = NULL;
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
BOOL GdiHelpInit()
{
InitDC();
return FlatSel!=NULL && pdeDisplay!=NULL;
}
#endif // DirectDraw