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.
1027 lines
28 KiB
1027 lines
28 KiB
/*
|
|
* DynaRes
|
|
*
|
|
* replacment for ChangeDisplaySettings EnumDisplaySettings to allow
|
|
* changing the bitdepth on the fly
|
|
*
|
|
* ToddLa
|
|
*
|
|
*/
|
|
#ifdef IS_16
|
|
#define DIRECT_DRAW
|
|
#endif
|
|
|
|
#ifdef DIRECT_DRAW
|
|
#include "ddraw16.h"
|
|
#else
|
|
#include <windows.h>
|
|
#include <print.h>
|
|
#include "gdihelp.h"
|
|
#include "dibeng.inc"
|
|
#endif
|
|
|
|
#define BABYSIT // if this is defined, work around bugs in the display driver
|
|
#define O95_HACK // enable the Office95 (any app bar) hack to prevent icons from being squished
|
|
#define SPI_HACK // enable the SPI_SETWORKAREA hack, when a app bar is up.
|
|
|
|
/*----------------------------------------------------------------------------*\
|
|
\*----------------------------------------------------------------------------*/
|
|
#undef Assert
|
|
#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 void FAR PASCAL SetMagicColors(HDC, DWORD, WORD);
|
|
extern UINT FAR PASCAL AllocCStoDSAlias(UINT);
|
|
extern void FAR PASCAL Death(HDC);
|
|
extern void FAR PASCAL Resurrection(HDC,LONG,LONG,LONG);
|
|
|
|
static char szClassName[] = "DynaResFullscreenWindow";
|
|
static char szDIBENG[] = "DIBENG";
|
|
static char szDISPLAY[] = "DISPLAY";
|
|
static char szUSER[] = "USER";
|
|
extern LONG FAR PASCAL DIBENG_Control(LPVOID,UINT,LPVOID,LPVOID);
|
|
|
|
extern HINSTANCE hInstApp;
|
|
|
|
#ifdef DIRECT_DRAW
|
|
extern bInOurSetMode;
|
|
#else
|
|
BOOL bInOurSetMode;
|
|
#endif
|
|
|
|
BOOL fNewDibEng;
|
|
BOOL fDirectDrawDriver;
|
|
|
|
BOOL InitDynaRes(void);
|
|
void PreStartMenuHack(DEVMODE FAR *);
|
|
void StartMenuHack(DEVMODE FAR *);
|
|
BOOL ForceSoftwareCursor(BOOL);
|
|
BOOL IsMatrox(void);
|
|
|
|
void PatchDisplay(int oem, BOOL patch);
|
|
void PatchControl(BOOL patch);
|
|
LONG FAR PASCAL _loadds Control(LPVOID lpDevice,UINT function,LPVOID lp_in_data,LPVOID lp_out_data);
|
|
|
|
#undef ChangeDisplaySettings
|
|
|
|
LONG WINAPI RealChangeDisplaySettings(LPDEVMODE pdm, DWORD flags)
|
|
{
|
|
return ChangeDisplaySettings(pdm, flags & ~CDS_EXCLUSIVE);
|
|
}
|
|
|
|
#ifdef DIRECT_DRAW
|
|
LONG DDAPI DD16_ChangeDisplaySettings(LPDEVMODE pdm, DWORD flags)
|
|
#else
|
|
LONG WINAPI DynaChangeDisplaySettings(LPDEVMODE pdm, DWORD flags)
|
|
#endif
|
|
{
|
|
LONG err;
|
|
HDC hdc;
|
|
int rc,bpp,w,h;
|
|
int new_rc,new_bpp;
|
|
HWND hwnd=NULL;
|
|
|
|
bInOurSetMode = TRUE;
|
|
|
|
flags &= ~CDS_EXCLUSIVE;
|
|
|
|
if (!InitDynaRes())
|
|
{
|
|
err = ChangeDisplaySettings(pdm, flags);
|
|
bInOurSetMode = FALSE;
|
|
return err;
|
|
}
|
|
|
|
if (flags & CDS_TEST)
|
|
{
|
|
err = ChangeDisplaySettings(pdm, flags | CDS_EXCLUSIVE);
|
|
bInOurSetMode = FALSE;
|
|
return err;
|
|
}
|
|
|
|
if (flags & CDS_FULLSCREEN)
|
|
PreStartMenuHack(pdm);
|
|
|
|
//
|
|
// try changing the mode normaly first
|
|
// if it works, we are done.
|
|
//
|
|
#ifdef BABYSIT
|
|
bInOurSetMode = (BOOL)2;
|
|
PatchControl(TRUE);
|
|
err = ChangeDisplaySettings(pdm, flags);
|
|
PatchControl(FALSE);
|
|
bInOurSetMode = TRUE;
|
|
#else
|
|
err = ChangeDisplaySettings(pdm, flags);
|
|
#endif
|
|
|
|
if (err == DISP_CHANGE_SUCCESSFUL)
|
|
{
|
|
if (flags & CDS_FULLSCREEN)
|
|
StartMenuHack(pdm);
|
|
bInOurSetMode = FALSE;
|
|
return err;
|
|
}
|
|
|
|
//
|
|
// if the mode is not valid dont even try.
|
|
//
|
|
err = ChangeDisplaySettings(pdm, CDS_EXCLUSIVE | CDS_TEST);
|
|
|
|
if (err != DISP_CHANGE_SUCCESSFUL)
|
|
{
|
|
bInOurSetMode = FALSE;
|
|
return err;
|
|
}
|
|
|
|
//
|
|
// get the current settings
|
|
//
|
|
hdc = GetDC(NULL);
|
|
rc = GetDeviceCaps(hdc, RASTERCAPS);
|
|
bpp = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
|
|
w = GetDeviceCaps(hdc, HORZRES);
|
|
h = GetDeviceCaps(hdc, VERTRES);
|
|
ReleaseDC(NULL, hdc);
|
|
|
|
//
|
|
// dont try to do a invalid change
|
|
//
|
|
if (pdm && (pdm->dmFields & DM_BITSPERPEL))
|
|
{
|
|
if ((int)pdm->dmBitsPerPel == bpp)
|
|
{
|
|
bInOurSetMode = FALSE;
|
|
return DISP_CHANGE_FAILED;
|
|
}
|
|
|
|
if (bpp <= 4 && (int)pdm->dmBitsPerPel != bpp)
|
|
{
|
|
bInOurSetMode = FALSE;
|
|
return DISP_CHANGE_RESTART;
|
|
}
|
|
|
|
if (bpp > 4 && (int)pdm->dmBitsPerPel <= 4)
|
|
{
|
|
bInOurSetMode = FALSE;
|
|
return DISP_CHANGE_RESTART;
|
|
}
|
|
}
|
|
|
|
#ifndef NOCREATEWINDOW
|
|
//
|
|
// bring up a "cover" window to hide all the activity of the mode
|
|
// change from the user. and brings up a wait cursor
|
|
//
|
|
// NOTE this does a little more than just hide the mode change
|
|
// from the user, it also makes sure to set a MONO hourglass cursor
|
|
// some display drivers dont like a software cursor being active
|
|
// durring a mode set, so we give them a mono one.
|
|
//
|
|
if (TRUE || !(flags & CDS_FULLSCREEN))
|
|
{
|
|
#define OCR_WAIT_DEFAULT 102
|
|
|
|
WNDCLASS cls;
|
|
|
|
cls.lpszClassName = szClassName;
|
|
cls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
|
cls.hInstance = hInstApp;
|
|
cls.hIcon = NULL;
|
|
cls.hCursor = (HCURSOR)LoadImage(NULL,MAKEINTRESOURCE(OCR_WAIT_DEFAULT),IMAGE_CURSOR,0,0,0);
|
|
cls.lpszMenuName = NULL;
|
|
cls.style = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
|
|
cls.lpfnWndProc = DefWindowProc;
|
|
cls.cbWndExtra = 0;
|
|
cls.cbClsExtra = 0;
|
|
|
|
RegisterClass(&cls);
|
|
|
|
hwnd = CreateWindowEx(WS_EX_TOPMOST|WS_EX_TOOLWINDOW,
|
|
szClassName, szClassName,
|
|
WS_POPUP|WS_VISIBLE, 0, 0, 10000, 10000,
|
|
NULL, NULL, hInstApp, NULL);
|
|
|
|
if (hwnd == NULL)
|
|
{
|
|
bInOurSetMode = FALSE;
|
|
return DISP_CHANGE_FAILED;
|
|
}
|
|
|
|
SetForegroundWindow(hwnd); // we want cursor focus
|
|
SetCursor(cls.hCursor); // set wait cursor.
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// no one gets to draw until we are done.
|
|
//
|
|
LockWindowUpdate(GetDesktopWindow());
|
|
|
|
DPF("Begin mode change from %dx%dx%d....", w,h,bpp);
|
|
|
|
//
|
|
// first thing we have to do is convert all DDBs and Pattern brushs
|
|
// to DIBSections so they will still work after the mode has changed.
|
|
//
|
|
ConvertObjects();
|
|
|
|
//
|
|
// convert all icons so they can be drawn correctly.
|
|
//
|
|
if (!fNewDibEng && !(flags & CDS_FULLSCREEN))
|
|
{
|
|
//ConvertIcons();
|
|
}
|
|
|
|
#ifdef BABYSIT
|
|
//
|
|
// the matrox driver is broken
|
|
// it has a global variable for bPaletized mode, and it only
|
|
// reads it if the mode is 8bpp.
|
|
//
|
|
if (!fDirectDrawDriver && bpp == 8 && IsMatrox())
|
|
{
|
|
static char szSystemIni[] = "system.ini";
|
|
static char szPalettized[] = "palettized";
|
|
static char szZero[] = "0";
|
|
static DEVMODE dm;
|
|
dm.dmSize = sizeof(DEVMODE);
|
|
dm.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
|
|
dm.dmBitsPerPel = 8;
|
|
dm.dmPelsWidth = 640;
|
|
dm.dmPelsHeight = 480;
|
|
|
|
DPF("**BABYSIT** Fixing the broken Matrox driver....");
|
|
WritePrivateProfileString(szDISPLAY,szPalettized,szZero,szSystemIni);
|
|
err = ChangeDisplaySettings(&dm, CDS_RESET | CDS_FULLSCREEN);
|
|
WritePrivateProfileString(szDISPLAY,szPalettized,NULL,szSystemIni);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// some drivers are total broken and we need to
|
|
// route some of its entry points to the DIBENG
|
|
//
|
|
// WARNING this can break some remote control programs!
|
|
//
|
|
#ifdef BABYSIT
|
|
if (!fDirectDrawDriver)
|
|
{
|
|
DPF("**BABYSIT** turning off OEMOutput....");
|
|
PatchDisplay(8, TRUE); // route OEMOutput to the DIBENG
|
|
|
|
DPF("**BABYSIT** turning off OEMDibBlt....");
|
|
PatchDisplay(19, TRUE); // route OEMDibBlt to the DIBENG
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// change the display settings.
|
|
//
|
|
PatchControl(TRUE);
|
|
|
|
DPF("Calling ChangeDisplaySettings....");
|
|
//
|
|
// NOTE USER will Yield unless CDS_FULLSCREEN is specifed
|
|
//
|
|
err = ChangeDisplaySettings(pdm, flags | CDS_EXCLUSIVE);
|
|
DPF("....ChangeDisplaySettings returns %d", err);
|
|
|
|
// get the new settings
|
|
//
|
|
hdc = GetDC(NULL);
|
|
new_rc = GetDeviceCaps(hdc, RASTERCAPS);
|
|
new_bpp = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
|
|
ReleaseDC(NULL, hdc);
|
|
|
|
//
|
|
// make sure the driver has not messed up its rastercaps!
|
|
// for example the QVision driver does not get this right.
|
|
//
|
|
if ((new_rc & RC_PALETTE) && new_bpp != 8)
|
|
{
|
|
DPF("**BABYSIT** drivers RC_PALETTE bit is messed up.");
|
|
err = DISP_CHANGE_RESTART; // err = DISP_CHANGE_FAILED;
|
|
}
|
|
|
|
//
|
|
// if the driver failed the mode set things could be real messed up
|
|
// reset the current mode, to try to recover.
|
|
//
|
|
#ifdef BABYSIT
|
|
if (err != DISP_CHANGE_SUCCESSFUL)
|
|
{
|
|
static DEVMODE dm;
|
|
dm.dmSize = sizeof(DEVMODE);
|
|
dm.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT|DM_DISPLAYFLAGS;
|
|
dm.dmBitsPerPel = bpp;
|
|
dm.dmPelsWidth = w;
|
|
dm.dmPelsHeight = h;
|
|
dm.dmDisplayFlags = 0;
|
|
|
|
DPF("**BABYSIT** mode set failed, going back to old mode.");
|
|
ChangeDisplaySettings(&dm, CDS_RESET | CDS_EXCLUSIVE | CDS_FULLSCREEN);
|
|
}
|
|
#endif
|
|
|
|
PatchControl(FALSE);
|
|
|
|
//
|
|
// call Death/Resurection this will kick drivers in the head
|
|
// about the mode change
|
|
//
|
|
if (!fDirectDrawDriver && err == 0 &&
|
|
(pdm == NULL || (flags & CDS_UPDATEREGISTRY)))
|
|
{
|
|
hdc = GetDC(NULL);
|
|
DPF("Calling Death/Resurection....");
|
|
SetCursor(NULL);
|
|
Death(hdc);
|
|
Resurrection(hdc,NULL,NULL,NULL);
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
|
|
//
|
|
// force a SW cursor, most drivers are broken and dont disable
|
|
// the HW cursor when changing modes.
|
|
//
|
|
#ifdef BABYSIT
|
|
if (!fDirectDrawDriver)
|
|
{
|
|
if (pdm == NULL && (flags & CDS_FULLSCREEN))
|
|
{
|
|
DPF("**BABYSIT** restoring HW cursor (return from fullscreen mode)");
|
|
ForceSoftwareCursor(FALSE);
|
|
}
|
|
else if (err == 0 && (new_bpp > 8 || GetSystemMetrics(SM_CXSCREEN) < 640))
|
|
{
|
|
DPF("**BABYSIT** Forcing a software cursor");
|
|
ForceSoftwareCursor(TRUE);
|
|
}
|
|
else
|
|
{
|
|
DPF("**BABYSIT** restoring HW cursor");
|
|
ForceSoftwareCursor(FALSE);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if 0 /// moved to Control patch
|
|
//
|
|
// we should now convert any DIBSections that used to be DDBs back to DDBs
|
|
// our code to find the right palette for a DDB is not too hot
|
|
// so a lot of DDBs will have wrong colors.
|
|
//
|
|
#if 1
|
|
ConvertBitmapsBack(FALSE);
|
|
#else
|
|
ConvertBitmapsBack(!(flags & CDS_FULLSCREEN));
|
|
#endif
|
|
#endif
|
|
|
|
//
|
|
// let other apps draw.
|
|
//
|
|
LockWindowUpdate(NULL);
|
|
|
|
//
|
|
// remove our "cover" window
|
|
//
|
|
if (hwnd)
|
|
{
|
|
DestroyWindow(hwnd);
|
|
UnregisterClass(szClassName, hInstApp);
|
|
}
|
|
|
|
//
|
|
// should we reload the wallpaper, because it got converted to
|
|
// a DDB by ConvertBitmapsBack
|
|
//
|
|
if (!(flags & CDS_FULLSCREEN))
|
|
{
|
|
DPF("Reloading wallpaper...");
|
|
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, NULL, 0);
|
|
}
|
|
|
|
//
|
|
// have all the apps deal with a color change
|
|
//
|
|
if (!(flags & CDS_FULLSCREEN))
|
|
{
|
|
//
|
|
//
|
|
//
|
|
// if we just post the WM_SYSCOLORCHANGE message to all apps
|
|
// a hidden office window will go back and forth Invalidating
|
|
// other office apps and re-sending the WM_SYSCOLORCHANGE message
|
|
// you either stack overflow, hang or XL just flashes for a few
|
|
// minutes.
|
|
//
|
|
// the "fix" is to not post the WM_SYSCOLORCHANGE message to
|
|
// this hidden window, we also have to make sure not to call
|
|
// SystemParametersInfo(SPI_SETDESKPATTERN) later in the code.
|
|
//
|
|
|
|
HWND hwnd;
|
|
HWND hwndX;
|
|
|
|
if (hwndX = FindWindow("File Open Message Window", "File Open Message Window"))
|
|
{
|
|
|
|
for (hwnd = GetWindow(GetDesktopWindow(), GW_CHILD);
|
|
hwnd;
|
|
hwnd = GetWindow(hwnd, GW_HWNDNEXT))
|
|
{
|
|
if (hwnd != hwndX)
|
|
PostMessage(hwnd, WM_SYSCOLORCHANGE, 0, 0);
|
|
}
|
|
|
|
// dont reload desktop pattern.
|
|
flags |= CDS_FULLSCREEN;
|
|
}
|
|
else
|
|
{
|
|
PostMessage(HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0);
|
|
}
|
|
}
|
|
|
|
//
|
|
// reload the desktop pattern
|
|
//
|
|
if (!(flags & CDS_FULLSCREEN) || pdm == NULL)
|
|
{
|
|
DPF("Reloading wallpaper pattern...");
|
|
SystemParametersInfo(SPI_SETDESKPATTERN, (UINT)-1, NULL, 0);
|
|
}
|
|
|
|
//
|
|
// we dont want the StartMenu to rebuild when we change modes
|
|
//
|
|
if (err == DISP_CHANGE_SUCCESSFUL)
|
|
{
|
|
if (flags & CDS_FULLSCREEN)
|
|
StartMenuHack(pdm);
|
|
}
|
|
|
|
bInOurSetMode = FALSE;
|
|
DPF("Done...");
|
|
return err;
|
|
}
|
|
|
|
#ifndef DCICOMMAND
|
|
#define DCICOMMAND 3075 // escape value
|
|
#endif
|
|
|
|
BOOL InitDynaRes()
|
|
{
|
|
int v;
|
|
HDC hdc;
|
|
HBRUSH hbr1, hbr2;
|
|
BOOL f=TRUE;
|
|
OSVERSIONINFO ver = {sizeof(OSVERSIONINFO)};
|
|
GetVersionEx(&ver);
|
|
|
|
// must be Windows95 build 950 or higher
|
|
|
|
if (LOWORD(GetVersion()) != 0x5F03)
|
|
{
|
|
DPF("Init: Windows version not 3.95.");
|
|
f = FALSE;
|
|
}
|
|
|
|
if (ver.dwMajorVersion != 4 ||
|
|
ver.dwMinorVersion != 0 ||
|
|
LOWORD(ver.dwBuildNumber) < 950)
|
|
{
|
|
DPF("Init: Windows version less than 4.0.950");
|
|
f = FALSE;
|
|
}
|
|
|
|
//
|
|
// we assume create/delete/create will get the same handle
|
|
//
|
|
hbr1 = CreateSolidBrush(RGB(1,1,1));
|
|
DeleteObject(hbr1);
|
|
hbr2 = CreateSolidBrush(RGB(2,2,2));
|
|
DeleteObject(hbr2);
|
|
|
|
if (hbr1 != hbr2)
|
|
{
|
|
DPF("Init: cant use Destroy/Create brush trick");
|
|
f = FALSE;
|
|
}
|
|
|
|
if (GetModuleHandle(szDIBENG) == 0)
|
|
{
|
|
DPF("Init: DIBENG not loaded");
|
|
f = FALSE;
|
|
}
|
|
|
|
hdc = GetDC(NULL);
|
|
|
|
// check the DIBENG version
|
|
v = 0x5250;
|
|
v = Escape(hdc, QUERYESCSUPPORT, sizeof(int), (LPVOID)&v, NULL);
|
|
|
|
if (v == 0)
|
|
{
|
|
DPF("Init: we dont have a new DIBENG");
|
|
fNewDibEng = FALSE;
|
|
}
|
|
else
|
|
{
|
|
DPF("Init: DIBENG version: %04X", v);
|
|
fNewDibEng = TRUE;
|
|
}
|
|
|
|
//
|
|
// see if the display supports DirectDraw
|
|
//
|
|
v = DCICOMMAND;
|
|
v = Escape(hdc, QUERYESCSUPPORT, sizeof(int), (LPVOID)&v, NULL);
|
|
|
|
if (v == 0 || v == 0x5250)
|
|
{
|
|
DPF("Init: display driver does not support DirectDraw");
|
|
fDirectDrawDriver = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (LOBYTE(v) == 0xFF)
|
|
v++;
|
|
|
|
DPF("Init: display driver supports DirectDraw: %04X", v);
|
|
fDirectDrawDriver = TRUE;
|
|
}
|
|
|
|
//
|
|
// must be a windows 4.0 mini driver.
|
|
//
|
|
if (GetDeviceCaps(hdc, DRIVERVERSION) < 0x0400)
|
|
{
|
|
DPF("Init: not a 4.0 display driver");
|
|
f = FALSE;
|
|
}
|
|
if (!(GetDeviceCaps(hdc, CAPS1) & C1_DIBENGINE))
|
|
{
|
|
DPF("Init: not a DIBENG display driver");
|
|
f = FALSE;
|
|
}
|
|
if (!(GetDeviceCaps(hdc, CAPS1) & C1_REINIT_ABLE))
|
|
{
|
|
DPF("Init: does not support C1_REINIT_ABLE");
|
|
f = FALSE;
|
|
}
|
|
ReleaseDC(NULL, hdc);
|
|
|
|
return f;
|
|
}
|
|
|
|
//
|
|
// we hook the OEMControl entry point in the display driver while a
|
|
// mode change is happening. GDI will issue a QUERYDIBSUPPORT escape
|
|
// right after the mode change happens so this is the first thing
|
|
// called after the mode changed worked. USER also issues a
|
|
// MOUSETRAILS escape.
|
|
//
|
|
// we need this hook for two reasons...
|
|
//
|
|
// 1. some display drivers are broken and dont set deFlags right
|
|
// we fix up the deFlags, we fix up the flags for them.
|
|
//
|
|
// 2. we rerealize all the gdi objects in this routine when
|
|
// USER calls us, this way all the pen/brushs/text colors
|
|
// are correct when user goes and rebuilds its bitmaps...
|
|
//
|
|
LONG FAR PASCAL _loadds Control(LPVOID lpDevice,UINT function,LPVOID lp_in_data,LPVOID lp_out_data)
|
|
{
|
|
DIBENGINE FAR *pde = (DIBENGINE FAR *)lpDevice;
|
|
LONG ret;
|
|
|
|
Assert(bInOurSetMode);
|
|
|
|
#ifdef BABYSIT
|
|
if (pde->deType == 0x5250)
|
|
{
|
|
if ((pde->deFlags & FIVE6FIVE) && pde->deBitsPixel != 16)
|
|
{
|
|
DPF("**BABYSIT** fixing FIVE6FIVE bit");
|
|
pde->deFlags &= ~FIVE6FIVE;
|
|
}
|
|
|
|
if ((pde->deFlags & PALETTIZED) && pde->deBitsPixel != 8)
|
|
{
|
|
DPF("**BABYSIT** fixing PALETTIZED bit");
|
|
pde->deFlags &= ~PALETTIZED;
|
|
}
|
|
|
|
if ((pde->deFlags & PALETTE_XLAT) && pde->deBitsPixel != 8)
|
|
{
|
|
DPF("**BABYSIT** fixing PALETTE_XLAT bit");
|
|
pde->deFlags &= ~PALETTE_XLAT;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// this is USER calling from LW_OEMDependentInit()
|
|
// force all GDI objects to be rerealized
|
|
//
|
|
if (function == MOUSETRAILS && bInOurSetMode != (BOOL)2)
|
|
{
|
|
//
|
|
// fix up the magic colors before we rerealize the brushes
|
|
// the "right" way to do this is to reset the UI colors
|
|
// by calling SetSysColors() but we dont want to send
|
|
// a sync WM_SYSCOLORCHANGE from here.
|
|
//
|
|
HDC hdc = GetDC(NULL);
|
|
if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
|
|
{
|
|
SetSystemPaletteUse(hdc, SYSPAL_STATIC);
|
|
SetMagicColors(hdc, GetSysColor(COLOR_3DSHADOW) , 8);
|
|
SetMagicColors(hdc, GetSysColor(COLOR_3DFACE) , 9);
|
|
SetMagicColors(hdc, GetSysColor(COLOR_3DHILIGHT), 246);
|
|
}
|
|
ReleaseDC(NULL, hdc);
|
|
|
|
//
|
|
// re-realize all GDI objects for the new mode.
|
|
//
|
|
ReRealizeObjects();
|
|
|
|
//
|
|
// we should now convert any DIBSections that used to be DDBs back to DDBs
|
|
// our code to find the right palette for a DDB is not too hot
|
|
// so a lot of DDBs will have wrong colors.
|
|
//
|
|
ConvertBitmapsBack(FALSE);
|
|
}
|
|
|
|
PatchControl(FALSE);
|
|
ret = DIBENG_Control(lpDevice,function,lp_in_data,lp_out_data);
|
|
PatchControl(TRUE);
|
|
|
|
return ret;
|
|
}
|
|
|
|
//
|
|
// patch
|
|
//
|
|
void Patch(LPCSTR szMod, LPCSTR szProc, FARPROC PatchFunc, LPDWORD PatchSave, BOOL fPatch)
|
|
{
|
|
LPDWORD pdw;
|
|
FARPROC x;
|
|
|
|
//
|
|
// ATM 2.5 has GetProcAddress patched to return some sort of
|
|
// thunk, that ends up totaly confusing us and we dont end up
|
|
// patching the DIBENG, we patch ATM's thunk.
|
|
//
|
|
// so when we want to patch DIBENG!OEMControl we use the value we
|
|
// *linked* to, not the value GetProcAddress returns.
|
|
//
|
|
if (lstrcmpi(szMod, szDIBENG) == 0 && szProc == MAKEINTATOM(3))
|
|
x = (FARPROC)DIBENG_Control;
|
|
else
|
|
x = GetProcAddress(GetModuleHandle(szMod), szProc);
|
|
|
|
if (x == NULL || PatchFunc == NULL)
|
|
return;
|
|
|
|
GlobalReAlloc((HGLOBAL)SELECTOROF(x), 0, GMEM_MODIFY|GMEM_MOVEABLE);
|
|
|
|
pdw = (LPDWORD)MAKELP(AllocCStoDSAlias(SELECTOROF(x)), OFFSETOF(x));
|
|
|
|
if (fPatch)
|
|
{
|
|
DPF("Patching %s!%d %04X:%04X", szMod, OFFSETOF(szProc), SELECTOROF(x), OFFSETOF(x));
|
|
if (PatchSave[0] == 0)
|
|
{
|
|
PatchSave[0] = pdw[0];
|
|
PatchSave[1] = pdw[1];
|
|
}
|
|
*((LPBYTE)pdw)++ = 0xEA; // JMP
|
|
*pdw = (DWORD)PatchFunc;
|
|
}
|
|
else
|
|
{
|
|
DPF("UnPatching %s!%d %04X:%04X", szMod, OFFSETOF(szProc), SELECTOROF(x), OFFSETOF(x));
|
|
if (PatchSave[0] != 0)
|
|
{
|
|
pdw[0] = PatchSave[0];
|
|
pdw[1] = PatchSave[1];
|
|
PatchSave[0] = 0;
|
|
PatchSave[1] = 0;
|
|
}
|
|
}
|
|
|
|
FreeSelector(SELECTOROF(pdw));
|
|
}
|
|
|
|
//
|
|
// hook the DIBENGs OEMControl() entry point, to jump to our own code
|
|
//
|
|
void PatchControl(BOOL patch)
|
|
{
|
|
static DWORD SaveBytes[2];
|
|
Patch(szDIBENG, MAKEINTATOM(3), (FARPROC)Control, SaveBytes, patch);
|
|
}
|
|
|
|
//
|
|
// patch a entry in the display driver to jump directly to the DIBENG
|
|
//
|
|
void PatchDisplay(int oem, BOOL patch)
|
|
{
|
|
FARPROC p;
|
|
|
|
#define MAX_DDI 35
|
|
static DWORD PatchBytes[MAX_DDI*2];
|
|
|
|
if (oem >= MAX_DDI)
|
|
return;
|
|
|
|
p = GetProcAddress(GetModuleHandle(szDIBENG), MAKEINTATOM(oem));
|
|
|
|
Patch(szDISPLAY, MAKEINTATOM(oem), p, &PatchBytes[oem*2], patch);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*\
|
|
\*----------------------------------------------------------------------------*/
|
|
|
|
#ifdef O95_HACK
|
|
|
|
static BOOL fOffice95Hack;
|
|
static char szDisplaySettings[] = "Display\\Settings";
|
|
static char szResolution[] = "Resolution";
|
|
static char szDD[] = "%d,%d";
|
|
|
|
//
|
|
// put back the right resolution into the registy key HKCC\Display\Settings
|
|
//
|
|
void Office95Hack()
|
|
{
|
|
if (fOffice95Hack)
|
|
{
|
|
HKEY hkey;
|
|
char ach[20];
|
|
int len;
|
|
|
|
DPF("Office95 hack: restoring registry");
|
|
|
|
if (RegOpenKey(HKEY_CURRENT_CONFIG, szDisplaySettings, &hkey) == 0)
|
|
{
|
|
len = wsprintf(ach, szDD, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
|
|
RegSetValueEx(hkey, szResolution, NULL, REG_SZ, ach, len);
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
fOffice95Hack = FALSE;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef SPI_HACK
|
|
|
|
BOOL FAR PASCAL _loadds SPI(UINT spi, UINT wParam, LPVOID lParam, UINT flags);
|
|
|
|
//
|
|
// patch USERs SystemParametersInfo function
|
|
//
|
|
void PatchSPI(BOOL patch)
|
|
{
|
|
static DWORD SaveBytes[2];
|
|
Patch(szUSER, MAKEINTATOM(483), (FARPROC)SPI, SaveBytes, patch);
|
|
}
|
|
|
|
BOOL FAR PASCAL _loadds SPI(UINT spi, UINT wParam, LPVOID lParam, UINT flags)
|
|
{
|
|
BOOL f;
|
|
|
|
if (spi == SPI_SETWORKAREA)
|
|
{
|
|
if (lParam)
|
|
DPF("Ignoring a SPI_SETWORKAREA [%d,%d,%d,%d] call", ((LPRECT)lParam)->left, ((LPRECT)lParam)->top, ((LPRECT)lParam)->right - ((LPRECT)lParam)->left, ((LPRECT)lParam)->bottom - ((LPRECT)lParam)->top);
|
|
else
|
|
DPF("Ignoring a SPI_SETWORKAREA lParam=NULL call");
|
|
return 0;
|
|
}
|
|
|
|
PatchSPI(FALSE);
|
|
f = SystemParametersInfo(spi, wParam, lParam, flags);
|
|
PatchSPI(TRUE);
|
|
return f;
|
|
}
|
|
#endif
|
|
|
|
/*----------------------------------------------------------------------------*\
|
|
\*----------------------------------------------------------------------------*/
|
|
|
|
//
|
|
// make the start menu not update in the background.
|
|
//
|
|
#define IDT_FAVOURITE 4
|
|
#define WNDCLASS_TRAYNOTIFY "Shell_TrayWnd"
|
|
|
|
LRESULT CALLBACK _loadds TrayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
#ifdef SPI_HACK
|
|
PatchSPI(FALSE);
|
|
#endif
|
|
#ifdef O95_HACK
|
|
Office95Hack();
|
|
#endif
|
|
DPF("StartMenu hack: killing timer to refresh start menu");
|
|
KillTimer(hwnd, IDT_FAVOURITE);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef SPI_HACK
|
|
RECT rcScreen;
|
|
RECT rcWork;
|
|
#endif
|
|
|
|
void PreStartMenuHack(DEVMODE FAR *pdm)
|
|
{
|
|
#ifdef SPI_HACK
|
|
SetRect(&rcScreen, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
|
|
SystemParametersInfo(SPI_GETWORKAREA, 0, (LPVOID)&rcWork, 0);
|
|
#endif
|
|
|
|
#ifdef O95_HACK
|
|
// make sure registry is put back
|
|
Office95Hack();
|
|
#endif
|
|
}
|
|
|
|
void StartMenuHack(DEVMODE FAR *pdm)
|
|
{
|
|
HWND hwndTray;
|
|
BOOL fAppBar=FALSE;
|
|
|
|
hwndTray = FindWindow(WNDCLASS_TRAYNOTIFY, NULL);
|
|
|
|
if (hwndTray == NULL)
|
|
{
|
|
DPF("Cant find tray window");
|
|
return;
|
|
}
|
|
|
|
// hack to get into the shells context, so we can clean up these hacks
|
|
PostMessage(hwndTray, WM_TIMER, 0, (LONG)TrayWndProc);
|
|
|
|
#ifdef SPI_HACK
|
|
{
|
|
RECT rc;
|
|
RECT rcTray;
|
|
|
|
//
|
|
// see if there are any other app bars around.
|
|
//
|
|
GetWindowRect(hwndTray, &rcTray);
|
|
SubtractRect(&rc, &rcScreen, &rcTray);
|
|
|
|
DPF("rcScreen [%d,%d,%d,%d]", rcScreen.left, rcScreen.top, rcScreen.right-rcScreen.left,rcScreen.bottom-rcScreen.top);
|
|
DPF("rcTray [%d,%d,%d,%d]", rcTray.left, rcTray.top, rcTray.right-rcTray.left,rcTray.bottom-rcTray.top);
|
|
DPF("rc [%d,%d,%d,%d]", rc.left, rc.top, rc.right-rc.left,rc.bottom-rc.top);
|
|
DPF("rcWork [%d,%d,%d,%d]", rcWork.left, rcWork.top, rcWork.right-rcWork.left,rcWork.bottom-rcWork.top);
|
|
|
|
if (!EqualRect(&rcScreen, &rcWork) && !EqualRect(&rc, &rcWork))
|
|
{
|
|
DPF("StartMenuHack: !!!!!there is a APP bar!!!!!!");
|
|
fAppBar = TRUE;
|
|
|
|
//
|
|
// Patch the USER!SystemParameterInto function, so when the
|
|
// shell does a SPI_SETWORKAREA call it will ignored
|
|
// this prevents windows from being "sqished" to fit inside
|
|
// the work area.
|
|
//
|
|
PatchSPI(TRUE);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef O95_HACK
|
|
//
|
|
// the shell does the following...
|
|
//
|
|
// read the HKEY_CURRENT_CONFIG\Display\Settings "Resloluton" key
|
|
// if this is LESS THAN the current display size, dont repark
|
|
// all the icons on the desktop because this is just a temporary
|
|
// mode set.
|
|
//
|
|
// this sound right, except the bug happens when we are returning
|
|
// to the "normal" mode, the shell will repark the icons because
|
|
// it checks for LESS THEN, not LESS THAN OR EQUAL, normaly this
|
|
// is fine because the re-park does nothing. when a app bar
|
|
// like Office95 is running it has not moved before the shell
|
|
// re-re-parks icons.
|
|
//
|
|
// what this hack does it set the size stored in the registry
|
|
// to be real large so the shell does not park icons.
|
|
// later we will but the right values back. we only need to
|
|
// do this if we are returning to the "normal" mode (ie pdm==NULL)
|
|
//
|
|
if (fAppBar && pdm == NULL)
|
|
{
|
|
HKEY hkey;
|
|
char ach[20];
|
|
int len;
|
|
|
|
fOffice95Hack = TRUE;
|
|
|
|
if (RegOpenKey(HKEY_CURRENT_CONFIG, szDisplaySettings, &hkey) == 0)
|
|
{
|
|
len = wsprintf(ach, szDD, 30000, 30000);
|
|
RegSetValueEx(hkey, szResolution, NULL, REG_SZ, ach, len);
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fOffice95Hack = FALSE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef BABYSIT
|
|
|
|
//
|
|
// force (or trick) the display driver into using a software cursor.
|
|
//
|
|
BOOL ForceSoftwareCursor(BOOL f)
|
|
{
|
|
int n=0;
|
|
|
|
//
|
|
// get the mouse trails setting from USER
|
|
//
|
|
SystemParametersInfo(SPI_GETMOUSETRAILS, 0, (LPVOID)&n, 0);
|
|
|
|
if (f)
|
|
{
|
|
//
|
|
// enable mouse trails, this will cause the display driver to
|
|
// turn off its hardware cursor
|
|
//
|
|
SystemParametersInfo(SPI_SETMOUSETRAILS, 2, NULL, 0);
|
|
|
|
//
|
|
// now tell the DIBENG to turn off mouse trails, the display driver
|
|
// will think they are still on...
|
|
//
|
|
PatchDisplay(3, TRUE); // route to DIBENG
|
|
SystemParametersInfo(SPI_SETMOUSETRAILS, n, NULL, 0);
|
|
PatchDisplay(3, FALSE); // back to DISPLAY
|
|
}
|
|
else
|
|
{
|
|
SystemParametersInfo(SPI_SETMOUSETRAILS, n, NULL, 0);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*\
|
|
\*----------------------------------------------------------------------------*/
|
|
|
|
BOOL IsMatrox()
|
|
{
|
|
char ach[80];
|
|
int len;
|
|
|
|
GetModuleFileName(GetModuleHandle(szDISPLAY), ach, sizeof(ach));
|
|
len = lstrlen(ach);
|
|
return len >= 7 && lstrcmpi(ach+len-7, "mga.drv") == 0;
|
|
}
|
|
|
|
#endif
|