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