From 6778f01eb9449012392189fe53860d33a95a8b0a Mon Sep 17 00:00:00 2001 From: gho tik Date: Sun, 3 Apr 2016 12:42:48 -0400 Subject: [PATCH] v2_03_54_src Former-commit-id: b58c6e078b773a7c67d434277da1587bc6f2a0a3 --- Include/dxwnd.h | 1 + build/dxwnd.0.ini | 31 - build/dxwnd.dll | 4 +- build/dxwnd.exe | 4 +- build/exports/Age of Empires III.dxw | 17 +- build/exports/Age of Wonders.dxw | 9 +- build/exports/Dark Colony (16 bit).dxw | 29 - build/exports/Dark Colony.dxw | 5 +- build/exports/Nox (GOG).dxw | 28 - build/exports/Nox (RIP).dxw | 28 - build/readme-relnotes.txt | 9 +- dll/ddraw.cpp | 4 + dll/dxhelper.cpp | 23 + dll/dxhelper.h | 1 + dll/dxhook.cpp | 12 +- dll/dxhook.h | 1 + dll/dxwcore.cpp | 50 +- dll/dxwcore.hpp | 9 +- dll/dxwnd.aps | Bin 47948 -> 58232 bytes dll/dxwnd.cpp | 2 +- dll/dxwnd.vs2008.suo | Bin 70144 -> 257024 bytes dll/dxwnd.vs2008.vcproj | 12 + dll/gdi32.cpp | 2186 ++++++++++++---- dll/hd3d.cpp | 8 + dll/hddraw.h | 1 + dll/kernel32.cpp | 25 +- dll/msims32.cpp | 74 + dll/shareddc.cpp | 461 ++++ dll/shareddc.hpp | 55 + dll/syslibs.h | 48 +- dll/user32.09.cpp | 3302 ++++++++++++++++++++++++ dll/user32.cpp | 966 +++++-- dll/virtualdc.cpp | 219 ++ host/TabCompat.cpp | 1 + host/TabSysLibs.cpp | 1 - host/TargetDlg.cpp | 107 +- host/TargetDlg.h | 3 + host/dxwndhost.aps | Bin 134244 -> 162172 bytes host/dxwndhost.cpp | 16 + host/dxwndhost.h | 6 + host/dxwndhost.rc | Bin 106948 -> 107888 bytes host/dxwndhost.vs2008.suo | Bin 69632 -> 80384 bytes host/dxwndhostView.cpp | 57 +- host/host.aps | Bin 47500 -> 47504 bytes host/resource | Bin 37632 -> 37982 bytes 45 files changed, 6912 insertions(+), 903 deletions(-) delete mode 100644 build/dxwnd.0.ini delete mode 100644 build/exports/Dark Colony (16 bit).dxw delete mode 100644 build/exports/Nox (GOG).dxw delete mode 100644 build/exports/Nox (RIP).dxw create mode 100644 dll/msims32.cpp create mode 100644 dll/shareddc.cpp create mode 100644 dll/shareddc.hpp create mode 100644 dll/user32.09.cpp create mode 100644 dll/virtualdc.cpp diff --git a/Include/dxwnd.h b/Include/dxwnd.h index d1ac928..bd9aee0 100644 --- a/Include/dxwnd.h +++ b/Include/dxwnd.h @@ -216,6 +216,7 @@ // seventh flags DWORD dxw.dwFlags7: #define LIMITDDRAW 0x00000001 // Limit the maximum available ddraw object version +#define DISABLEDISABLEALTTAB 0x00000002 // Disables the compatibility patch that disables the Alt-Tab key and other special combinations // eighth flags DWORD dxw.dwFlags8: diff --git a/build/dxwnd.0.ini b/build/dxwnd.0.ini deleted file mode 100644 index be2c649..0000000 --- a/build/dxwnd.0.ini +++ /dev/null @@ -1,31 +0,0 @@ -[window] -posx=50 -posy=50 -sizx=320 -sizy=200 -lang=default -;lang=automatic -;updatepaths=1 -;debug=1 -;multiprocesshook=0 -;checkadmin=0 -[texture] -MinTexX=16 -MaxTexX=0 -MinTexY=16 -MaxTexY=0 -[keymapping] -timetoggle=0x72 -altf4=0x73 -timeslow=0x74 -timefast=0x75 -cliptoggle= -refresh= -logtoggle= -plocktoggle= -fpstoggle= -printscreen=0x7B -corner=0x7A -freezetime=0x79 - - diff --git a/build/dxwnd.dll b/build/dxwnd.dll index 8b2a2c0..db4fbd5 100644 --- a/build/dxwnd.dll +++ b/build/dxwnd.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:935f85ba0560e2c0a319ea4a007c0f24de314cc7207710fdcd4d41e6a4fbb39a -size 593920 +oid sha256:b9f75f7b545dbfc03a38bf99d8260cbbe4dee01c82b7955c61769a126c643b82 +size 622080 diff --git a/build/dxwnd.exe b/build/dxwnd.exe index 71ed249..a1deeb2 100644 --- a/build/dxwnd.exe +++ b/build/dxwnd.exe @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:82bd1f60071207b5033f2deade63c46438a048357e3cb0e4d5aa5b379da92186 -size 545792 +oid sha256:91dd24684d705c58f1e0bb5870715a997c93b285d02075571f0f8ef87068adec +size 548352 diff --git a/build/exports/Age of Empires III.dxw b/build/exports/Age of Empires III.dxw index b52c0c3..229b1b7 100644 --- a/build/exports/Age of Empires III.dxw +++ b/build/exports/Age of Empires III.dxw @@ -5,11 +5,11 @@ module0= opengllib0= ver0=0 coord0=0 -flag0=-394124766 +flag0=1753358370 flagg0=134217728 flagh0=20 -flagi0=4194304 -tflag0=0 +flagi0=0 +tflag0=3 initx0=0 inity0=0 minx0=0 @@ -22,14 +22,3 @@ sizx0=800 sizy0=600 maxfps0=0 initts0=0 -launchpath0= -notes0= -registry0= -flagj0=0 -flagk0=0 -flagl0=0 -flagm0=0 -winver0=0 -maxres0=0 -swapeffect0=0 -maxddinterface0=7 diff --git a/build/exports/Age of Wonders.dxw b/build/exports/Age of Wonders.dxw index 0162307..9468df5 100644 --- a/build/exports/Age of Wonders.dxw +++ b/build/exports/Age of Wonders.dxw @@ -6,7 +6,7 @@ module0= opengllib0= ver0=0 coord0=0 -flag0=679477794 +flag0=679477792 flagg0=1207959552 flagh0=20 flagi0=205520900 @@ -26,10 +26,3 @@ initts0=0 winver0=0 maxres0=-1 flagj0=128 -notes0= -registry0= -flagk0=65536 -flagl0=0 -flagm0=0 -swapeffect0=0 -maxddinterface0=7 diff --git a/build/exports/Dark Colony (16 bit).dxw b/build/exports/Dark Colony (16 bit).dxw deleted file mode 100644 index 93cc224..0000000 --- a/build/exports/Dark Colony (16 bit).dxw +++ /dev/null @@ -1,29 +0,0 @@ -[target] -title0=Dark Colony (16 bit) -path0=D:\Games\DarkColony\DCOLONY\DC16.EXE -launchpath0= -module0= -opengllib0= -notes0= -registry0= -ver0=0 -coord0=0 -flag0=134234166 -flagg0=1207959552 -flagh0=20 -flagi0=4194308 -flagj0=67108992 -flagk0=0 -flagl0=0 -flagm0=0 -tflag0=0 -posx0=50 -posy0=50 -sizx0=800 -sizy0=600 -maxfps0=0 -initts0=0 -winver0=0 -maxres0=-1 -swapeffect0=0 -maxddinterface0=7 diff --git a/build/exports/Dark Colony.dxw b/build/exports/Dark Colony.dxw index 6a44e7b..f23cefd 100644 --- a/build/exports/Dark Colony.dxw +++ b/build/exports/Dark Colony.dxw @@ -5,7 +5,7 @@ module0= opengllib0= ver0=0 coord0=0 -flag0=134234166 +flag0=134218274 flagg0=1207959552 flagh0=20 flagi0=4194308 @@ -30,6 +30,3 @@ notes0= registry0= flagk0=0 swapeffect0=0 -flagl0=0 -flagm0=0 -maxddinterface0=7 diff --git a/build/exports/Nox (GOG).dxw b/build/exports/Nox (GOG).dxw deleted file mode 100644 index 15381e8..0000000 --- a/build/exports/Nox (GOG).dxw +++ /dev/null @@ -1,28 +0,0 @@ -[target] -title0=Nox (GOG) -path0=D:\Games\Nox GOG\Game.exe -launchpath0= -module0= -opengllib0= -notes0= -registry0= -ver0=0 -coord0=0 -flag0=681574434 -flagg0=1207959552 -flagh0=20 -flagi0=134217732 -flagj0=4224 -flagk0=65536 -flagl0=0 -flagm0=0 -tflag0=0 -posx0=50 -posy0=50 -sizx0=800 -sizy0=600 -maxfps0=0 -initts0=0 -winver0=0 -maxres0=-1 -swapeffect0=0 diff --git a/build/exports/Nox (RIP).dxw b/build/exports/Nox (RIP).dxw deleted file mode 100644 index 494e2fd..0000000 --- a/build/exports/Nox (RIP).dxw +++ /dev/null @@ -1,28 +0,0 @@ -[target] -title0=Nox (RIP) -path0=D:\Games\Nox RIP\GAME.EXE -launchpath0= -module0= -opengllib0= -notes0= -registry0= -ver0=0 -coord0=2 -flag0=681574434 -flagg0=1207959568 -flagh0=20 -flagi0=138412036 -flagj0=5248 -flagk0=65536 -flagl0=0 -flagm0=0 -tflag0=0 -posx0=50 -posy0=50 -sizx0=800 -sizy0=600 -maxfps0=0 -initts0=0 -winver0=0 -maxres0=-1 -swapeffect0=0 diff --git a/build/readme-relnotes.txt b/build/readme-relnotes.txt index aa60f11..4614622 100644 --- a/build/readme-relnotes.txt +++ b/build/readme-relnotes.txt @@ -1022,4 +1022,11 @@ fix: used fake resolutions also in USER32 EnumDisplaySettings fix: avoid hooking directinput dlls if not requested when loaded dynamically fix: added recovery of lost device in DirectInput GetDeviceData method fix: changed SetHook so that it can get function pointers without necessarily replacing them -add: option "Limit ddraw interface" to exclude support for IDirectDrawInterface greater than limit (range 1-7) \ No newline at end of file +add: option "Limit ddraw interface" to exclude support for IDirectDrawInterface greater than limit (range 1-7) + +v2.03.53(skipped) +v2.03.54 +add: syslib shared dc mode preliminary implementation, thank to Narzoul's ideas. Works for "MS Golf 98" and "Deadlock II rel. 1.2" +fix: handling of cursor hide/show for programs that don't go through the message window ("Deadlock II rel. 1.2") +add: /R:n command line option to automatically start DxWnd in icon tray, run the n-th program in configuration and terminate. +add: option to disable the disabling of Alt-Tab key through SetWindowHooks through WH_KEYBOARD_LL event. Mae it posssible to use Alt-Tab key on "Dungeon Kepper II". \ No newline at end of file diff --git a/dll/ddraw.cpp b/dll/ddraw.cpp index df09254..81d3510 100644 --- a/dll/ddraw.cpp +++ b/dll/ddraw.cpp @@ -148,6 +148,8 @@ DirectDrawCreateEx_Type pDirectDrawCreateEx = NULL; DirectDrawEnumerate_Type pDirectDrawEnumerate = NULL; DirectDrawEnumerateEx_Type pDirectDrawEnumerateEx = NULL; DirectDrawCreateClipper_Type pDirectDrawCreateClipper = NULL; +HandleDDThreadLock_Type pAcquireDDThreadLock = NULL; +HandleDDThreadLock_Type pReleaseDDThreadLock = NULL; /* DirectDraw hook pointers */ QueryInterface_Type pQueryInterfaceD1; @@ -310,6 +312,8 @@ static HookEntry_Type ddHooks[]={ {HOOK_HOT_CANDIDATE, "DirectDrawEnumerateA", (FARPROC)NULL, (FARPROC *)&pDirectDrawEnumerate, (FARPROC)extDirectDrawEnumerate}, {HOOK_HOT_CANDIDATE, "DirectDrawEnumerateExA", (FARPROC)NULL, (FARPROC *)&pDirectDrawEnumerateEx, (FARPROC)extDirectDrawEnumerateEx}, {HOOK_HOT_CANDIDATE, "DirectDrawCreateClipper", (FARPROC)NULL, (FARPROC *)&pDirectDrawCreateClipper, (FARPROC)extDirectDrawCreateClipper}, + {HOOK_HOT_CANDIDATE, "AcquireDDThreadLock", (FARPROC)NULL, (FARPROC *)&pAcquireDDThreadLock, (FARPROC)NULL}, + {HOOK_HOT_CANDIDATE, "ReleaseDDThreadLock", (FARPROC)NULL, (FARPROC *)&pReleaseDDThreadLock, (FARPROC)NULL}, //{HOOK_IAT_CANDIDATE, "DirectDrawEnumerateW", (FARPROC)NULL, (FARPROC *)&pDirectDrawEnumerateW, (FARPROC)extDirectDrawCreate}, //{HOOK_IAT_CANDIDATE, "DirectDrawEnumerateExW", (FARPROC)NULL, (FARPROC *)&pDirectDrawEnumerateExW, (FARPROC)extDirectDrawCreate}, {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator diff --git a/dll/dxhelper.cpp b/dll/dxhelper.cpp index 9b7dcac..60a1b9f 100644 --- a/dll/dxhelper.cpp +++ b/dll/dxhelper.cpp @@ -1907,4 +1907,27 @@ char *ExplainPixelFormat(LPDDPIXELFORMAT ddpfPixelFormat) strcat(sBuf, sItem); } return sBuf; +} + +char *GetObjectTypeStr(HDC hdc) +{ + char *s; + switch (GetObjectType(hdc)){ + case OBJ_PEN: s="PEN"; break; + case OBJ_BRUSH: s="BRUSH"; break; + case OBJ_DC: s="DC"; break; + case OBJ_METADC: s="METADC"; break; + case OBJ_PAL: s="PAL"; break; + case OBJ_FONT: s="FONT"; break; + case OBJ_BITMAP: s="BITMAP"; break; + case OBJ_REGION: s="REGION"; break; + case OBJ_METAFILE: s="METAFILE"; break; + case OBJ_MEMDC: s="MEMDC"; break; + case OBJ_EXTPEN: s="EXTPEN"; break; + case OBJ_ENHMETADC: s="ENHMETADC"; break; + case OBJ_ENHMETAFILE: s="ENHMETAFILE"; break; + case OBJ_COLORSPACE: s="COLORSPACE"; break; + default: s="unknown"; break; + } + return s; } \ No newline at end of file diff --git a/dll/dxhelper.h b/dll/dxhelper.h index 7eadb97..c116b48 100644 --- a/dll/dxhelper.h +++ b/dll/dxhelper.h @@ -54,3 +54,4 @@ extern char *ExplainDICooperativeFlags(DWORD); extern char *ExplainRegionType(DWORD); extern char *ExplainPixelFormat(LPDDPIXELFORMAT); extern char *ExplainZBufferBitDepths(DWORD); +extern char *GetObjectTypeStr(HDC); diff --git a/dll/dxhook.cpp b/dll/dxhook.cpp index 1c3461e..5ea5551 100644 --- a/dll/dxhook.cpp +++ b/dll/dxhook.cpp @@ -8,6 +8,7 @@ #include #include "dxwnd.h" #include "dxwcore.hpp" +#include "shareddc.hpp" #include "dxhook.h" #include "glhook.h" #include "glidehook.h" @@ -28,6 +29,7 @@ dxwCore dxw; dxwSStack dxwss; dxwWStack dxwws; +dxwSDC sdc; extern LRESULT CALLBACK MessageHook(int, WPARAM, LPARAM); @@ -1368,7 +1370,7 @@ void HookInit(TARGETMAP *target, HWND hwnd) InitScreenParameters(); if(hwnd) HookWindowProc(hwnd); // in fullscreen mode, messages seem to reach and get processed by the parent window - if((!dxw.Windowize) && hwnd) HookWindowProc(GetParent(hwnd)); + if((!dxw.Windowize) && hwnd) HookWindowProc(dxw.hParentWnd); // initialize window: if // 1) not in injection mode (hwnd != 0) and @@ -1409,8 +1411,9 @@ FARPROC RemapLibrary(LPCSTR proc, HMODULE hModule, HookEntry_Type *Hooks) void *remapped_addr; for(; Hooks->APIName; Hooks++){ if (!strcmp(proc,Hooks->APIName)){ - if((((dxw.dwFlags4 & HOTPATCH) && (Hooks->HookStatus == HOOK_HOT_CANDIDATE)) || // hot patch candidate still to process - or - ((dxw.dwFlags4 & HOTPATCHALWAYS) && (Hooks->HookStatus != HOOK_HOT_LINKED)))){ // force hot patch and not already hooked + if ((Hooks->HookStatus == HOOK_HOT_REQUIRED) || + ((dxw.dwFlags4 & HOTPATCH) && (Hooks->HookStatus == HOOK_HOT_CANDIDATE)) || // hot patch candidate still to process - or + ((dxw.dwFlags4 & HOTPATCHALWAYS) && (Hooks->HookStatus != HOOK_HOT_LINKED))){ // force hot patch and not already hooked if(!Hooks->OriginalAddress) { Hooks->OriginalAddress=(*pGetProcAddress)(hModule, Hooks->APIName); @@ -1462,7 +1465,8 @@ void HookLibrary(HMODULE hModule, HookEntry_Type *Hooks, char *DLLName) // continue; //} - if((((dxw.dwFlags4 & HOTPATCH) && (Hooks->HookStatus == HOOK_HOT_CANDIDATE)) || // hot patch candidate still to process - or + if(((Hooks->HookStatus == HOOK_HOT_REQUIRED) || + ((dxw.dwFlags4 & HOTPATCH) && (Hooks->HookStatus == HOOK_HOT_CANDIDATE)) || // hot patch candidate still to process - or ((dxw.dwFlags4 & HOTPATCHALWAYS) && (Hooks->HookStatus != HOOK_HOT_LINKED))) // force hot patch and not already hooked && Hooks->StoreAddress){ // and save ptr available diff --git a/dll/dxhook.h b/dll/dxhook.h index db3cd1e..aab2799 100644 --- a/dll/dxhook.h +++ b/dll/dxhook.h @@ -47,6 +47,7 @@ extern FARPROC Remap_DInput8_ProcAddress(LPCSTR, HMODULE); typedef enum { HOOK_IAT_CANDIDATE = 0, HOOK_HOT_CANDIDATE, + HOOK_HOT_REQUIRED, HOOK_IAT_LINKED, HOOK_HOT_LINKED } HookEntry_Status; diff --git a/dll/dxwcore.cpp b/dll/dxwcore.cpp index 0a70508..bfd77f2 100644 --- a/dll/dxwcore.cpp +++ b/dll/dxwcore.cpp @@ -11,6 +11,7 @@ #include "d3d9.h" extern GetDC_Type pGetDC; extern ReleaseDC_Type pReleaseDC; +extern HandleDDThreadLock_Type pReleaseDDThreadLock; /* ------------------------------------------------------------------ */ // Internal function pointers @@ -72,8 +73,12 @@ void dxwCore::SetFullScreen(BOOL fs) BOOL dxwCore::IsFullScreen() { - //if(!Windowize) return FALSE; - return FullScreen; + return (Windowize && FullScreen); +} + +BOOL dxwCore::IsToRemap(HDC hdc) +{ + return (Windowize && FullScreen && (OBJ_DC == (*pGetObjectType)(hdc))); } void dxwCore::InitTarget(TARGETMAP *target) @@ -128,9 +133,10 @@ void dxwCore::InitTarget(TARGETMAP *target) iRatioX = iSizX ? iSizX : 800; iRatioY = iSizY ? iSizY : 600; - GDIEmulationMode = GDIMODE_STRETCHED; // default + GDIEmulationMode = GDIMODE_NONE; // default if (dwFlags2 & GDISTRETCHED) GDIEmulationMode = GDIMODE_STRETCHED; if (dwFlags3 & GDIEMULATEDC) GDIEmulationMode = GDIMODE_EMULATED; + if (dwFlags6 & SHAREDDC) GDIEmulationMode = GDIMODE_SHAREDDC; } void dxwCore::SetScreenSize(void) @@ -367,19 +373,6 @@ POINT dxwCore::FixCursorPos(POINT prev) if (h) curr.y = (curr.y * dxw.GetScreenHeight()) / h; } - //if(dxw.dwFlags4 & FRAMECOMPENSATION){ - // static int dx, dy, todo=TRUE; - // if (todo){ - // POINT FrameOffset = dxw.GetFrameOffset(); - // dx=FrameOffset.x; - // dy=FrameOffset.y; - // OutTraceC("GetCursorPos: frame compensation=(%d,%d)\n", dx, dy); - // todo=FALSE; - // } - // curr.x += dx; - // curr.y += dy; - //} - if((dxw.dwFlags1 & ENABLECLIPPING) && lpClipRegion){ // v2.1.93: // in clipping mode, avoid the cursor position to lay outside the valid rect @@ -400,14 +393,6 @@ POINT dxwCore::FixCursorPos(POINT prev) if (curr.y >= (LONG)dxw.GetScreenHeight()-CLIP_TOLERANCE) curr.y=dxw.GetScreenHeight()-1; } - //if(0){ // Scrolling Slow-down - // if( (curr.x <= 0) || - // (curr.x >= (LONG)(dxw.GetScreenWidth()-1)) || - // (curr.y <= 0) || - // (curr.y >= (LONG)(dxw.GetScreenHeight()-1))) - // (*pSleep)(800); - //} - return curr; } @@ -1632,7 +1617,7 @@ void dxwCore::ResetEmulatedDC() BOOL dxwCore::IsVirtual(HDC hdc) { - return (hdc==VirtualHDC) && (dwFlags3 & GDIEMULATEDC); + return (hdc==VirtualHDC) && (GDIEmulationMode == GDIMODE_EMULATED); } HDC dxwCore::AcquireSharedDC(HWND hwnd) @@ -1640,12 +1625,15 @@ HDC dxwCore::AcquireSharedDC(HWND hwnd) extern HDC hFlippedDC; LPDIRECTDRAWSURFACE lpDDSPrim; lpDDSPrim = dxwss.GetPrimarySurface(); - if (lpDDSPrim) (*pGetDC)(lpDDSPrim, &hFlippedDC); - while((hFlippedDC == NULL) && lpDDSPrim) { - OutTraceDW("AcquireSharedDC: found primary surface with no DC, unref lpdds=%x\n", lpDDSPrim); - dxwss.UnrefSurface(lpDDSPrim); - lpDDSPrim = dxwss.GetPrimarySurface(); - if (lpDDSPrim) (*pGetDC)(lpDDSPrim, &hFlippedDC); + if (lpDDSPrim) { + if(pReleaseDDThreadLock)(*pReleaseDDThreadLock)(); + (*pGetDC)(lpDDSPrim, &hFlippedDC); + while((hFlippedDC == NULL) && lpDDSPrim) { + OutTraceDW("AcquireSharedDC: found primary surface with no DC, unref lpdds=%x\n", lpDDSPrim); + dxwss.UnrefSurface(lpDDSPrim); + lpDDSPrim = dxwss.GetPrimarySurface(); + if (lpDDSPrim) (*pGetDC)(lpDDSPrim, &hFlippedDC); + } } if (!(hwnd == dxw.GethWnd())) { POINT father, child, offset; diff --git a/dll/dxwcore.hpp b/dll/dxwcore.hpp index 238e441..611be01 100644 --- a/dll/dxwcore.hpp +++ b/dll/dxwcore.hpp @@ -56,6 +56,7 @@ public: // methods void SetFullScreen(BOOL); void SetFullScreen(BOOL, int); BOOL IsFullScreen(); + BOOL IsToRemap(HDC); BOOL IsDesktop(HWND); BOOL IsRealDesktop(HWND); POINT FixCursorPos(POINT); @@ -357,8 +358,12 @@ typedef enum { DXVK_SIZE }; -#define GDIMODE_STRETCHED 0 -#define GDIMODE_EMULATED 1 +typedef enum { + GDIMODE_NONE = 0, + GDIMODE_STRETCHED, + GDIMODE_EMULATED, + GDIMODE_SHAREDDC +}; typedef HRESULT (WINAPI *ColorConversion_Type)(LPDIRECTDRAWSURFACE, RECT, LPDIRECTDRAWSURFACE *); extern ColorConversion_Type pColorConversion; diff --git a/dll/dxwnd.aps b/dll/dxwnd.aps index ea03d6582138b8db4029713356ffd15b66f4ca7a..7123e81aa03e857cb20a9a1a84fd2762e028acbc 100644 GIT binary patch delta 7979 zcmeHMYfMx}6rSZ_vQ$G=K%NWBYjtJWg++<54VJRa3I-_hj3BIwAPD$Ckfac*k*Kj$ zaZ;6ps#SlO^oKzt3a0T#Q^Jq_X^a{Znx=n9P1Rp*(=;UXyL)%X@!r|xkv3_R%j2Fo zb6#`KxpU6F^TVG3e@z9RPtaI~^hxIZzYx-xQ(Mqe)zMhnomp?O)^D-a@7;IQS=-pw zmfqgke6X#_THDxjtfMjgh->uNAI0>%W-icTvCzY%;qu?;xZCLmpUC&) zWy`r6>51~X)r7m~Z{@B~Ha3||)z#JX>&iMU!%=gk>%SPip>_A}-OyUKPOH^sWo0ql z0BCAW-8vp2!}QCVDmcVMm*)sOT~jAH&=HuPo=%U~MFmGiVe!Ds2ULgBD|^ytSxGb^ zF&vtfmX?x|l8}&)l$2yN8bMM;b6qjG7wa*Gx!;K{1aR}_&5{a(*=)|q$q^BGa2XjH zpaHGj5ET{mX47NIGatahGD20-Twd866!hR>br_e*73jvNG_%!$Ji-l2VGuGy7x!Do>s~DOSc| zb8~auYwIU?S_=ycdAULuOGoS#%8(G#)6<+-F?jXrRX78@@Jdfl4==x;A29gQqep6G zz#t#R8aV9b%a>(kSlF&zyO>Nd&>#B}*@hiSu`(q5jT<*Ov0|{Hp@F3xb`!A;mtrSFae}1IWoeIyxE_7RJ;t06TO`OUvBc9Ip}5`+gAT#ttmygZo@#zrB>NoJJyTB`|(;%ia7n9j~lSm&)77cXAqCx!6f z;Gnkx;C|u41tArWym|Acx5_{ll9Hbk!UF>X2*2AZtPLv^Qt?Ra$k@lgk#9hv`M2u& z_3L;9LF>>XR^#L2ydVbSL0!9cEvSl7CSuTEJ%9e3P0r5FwzszbI2TWyP%j?5B;c}_i4E{H&BNL_uMAcDE#bZ>}k)IU8ORA1S2|RM? z)sg2G!i%VmLOve3i0a6b3*n_!N1+fI>7zRO;#gL7GE+mZIfEt7d2%)cu~q0VkPxtFWE7<=>l4f!ca1*hP z4UY!~=slYq(FVCd-T{Vv~kf-#kdjsnQN3t~gzFCO>)Cc~d4}9Q+xnCfk z9r==6l8pU0Q(B~A*-JP$CN{SeNfLRXAs7(iAXOwE_j%erv0j63niB@it)V`1u=KI{ zSNhY0Rg*>6PFgk9)IJ#>u)TyDapu`D8T8)$J>D|WOiL!i11uf%Z>KzUtIs>tB26VG u40^|{kV=RJu66_XXWLH5$OxUC)U7%cK*-z-4SAqj^%Ulv|Cy#g(ES4)J7qcm delta 6490 zcmeHMZA_C_6u#w~%mh%XutG~=$~P2>Mwy#J)QQaqXaSjJxbdM)#PCgtV}0F3F^)mK z2xGFu7=JDM;Y8v#mdLMV$z0-QVnX7gVq#{pWbV)8he`LG`$9|Gw@8%*fB2HVz4tlK zJ?GwY?!7%H%>ER7NJ!AESmL0aLqxF`~{91#tw!m21-r8-cKXN3e z-P+J-J#@Ieq194v>pEJW(^|(EdyT79`frDSFSQ$2_E}l`1_N&_)9qd^7w})pQccUE zEGH+Yw6v6eP@ysH+qW+}J9}BQ@|eA;J6~yfrUzbDKV>{~<}L#N*j%G__0TXF3`Ipn z=gytu|CnQWNX4!wmlWG;|Ni|vud*i6h4JeZb^k}t!|H(p2Vk{|M^}ffa#==$Cs)_3 zUI@r-?x?N`>>#|XfqZoceWUA*Q0$iNGA%1Bqsz3sva)iyE>p}Gw=_RqqvnG(kt_Q< zW;Cv}{b1wfVE*O%SrsA3E}E%Fb+IVISa{d`6h}u#zhHLI$euht64j`k2|# z6yONJa6zQ`FBM}x3NiRJfnr{EQYZmp;e^4!6Ny$c=Z=BVQM*{gEKOVRK%HNNSPqSq zA5!HN5dZ!TC({SO zN=iyeNy*3v;HTgFB3-PnGV;5%8uMb5z-5?iK|uj8Dp#A4b!28{2ChPRL~d?wVPT=T z$n)~@&{L)bh{ngq-@bhtTD7LAD0hAmpcXeB^V+gy3-swtb#-+wzWfavHjIsp34IQS zBQ-VEZR)vN&@eDCAoN|hZ~=SlxwNo%)~&+$ollG1J1H?Sae8_hxR#qvY@5rfu}Z$ZTFcAI!_=H}U$^laC$fo)d}Ys` zJ>(8GwBSDQT#AuTbqF3NZL`?~@7Aqb3cRe&d3`7;1rKY&<>IX``lR3i#&Hn5&dyHX z8;E~&GJ7s-N4R==dO+3in&M5(U0&qnrnwoGdytOQnS$I?Z_u+4yP8S*) z+Su3_5)z`-YL~oypVvMz2Ux}1|E&BEW4;%Bi~& z=9vo5@svsrp<8lKB)qS0uJnlLo1Y?*_z{uzhEGmTUKU(YdNi}HW_AqNq`*W4Fi1^; zCM9Z70f50M1q61PN)J&L$n}T-uaQ^~MUAp3=Bp5cyJ@g+-5DC(3`nkJQ1Hw)M*;ed zAja${JtR4)KQ_k$ibdFI`-|lWo_G=D6%haa4k!lRrH7p?Np8#3qAJHThyXzpi}Rp{ zQ|X~93qu0P%$4mYQ4pN=xO?P|MivI=Rq4#qANZ#=)Iqg^S z%e~x8MLX{QHoVE+z)7MHyTPsZQ&jo9|9)!FH;ij%5*)*;!`8w=r^;rx5yyx|d!tIRx+0NK* gR>g`TcRGLep__vspWvGwXv5B{7@NAr-+Q3_4+bcIga7~l diff --git a/dll/dxwnd.cpp b/dll/dxwnd.cpp index babde65..56f8f1e 100644 --- a/dll/dxwnd.cpp +++ b/dll/dxwnd.cpp @@ -27,7 +27,7 @@ along with this program. If not, see . #include "TlHelp32.h" -#define VERSION "2.03.52" +#define VERSION "2.03.54" #define DDTHREADLOCK 1 //#define LOCKTHREADS diff --git a/dll/dxwnd.vs2008.suo b/dll/dxwnd.vs2008.suo index 1c97efc80f69bf6d73417195eb55a1fdbe9f4f84..997cf29d751888641a9a1db8770fea1679cbc0ad 100644 GIT binary patch literal 257024 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

FlI_cKiL3xJAQAN~7?d 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%0D;r*tc+6f|9FXu1aWLh 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

9+9xeB^dTZJUQ?t8`qb;W}ho1 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 M-{01&^8e!Ue~ZWIH~;_u delta 2627 zcmbVOeQZZHILRE!2vU8sk zV079ayVlS5o^$WJ@7(k8yDxXul{=;88}Nz0D*6H@o0~C(I<3&Q@J#ju6b2TYRi>fl z?(FRBJcelg`-EY_i-g03e-*M7MRgM_5;bbr_0j3WuixEz1vt&5USncJy`cMOOqjVBD%DO6_3#~HH2D1Jz;*bj>eA?mOP+a zO5+AXBQwux8F2sjsptFMV~%x)4@FkK6LPG@(KwHZl>STnbt|aYR0nP{4{+22t!9he z1{!GexI+|*OEqcuDKPh!UEr3DL(VQS6^>~?A$=u?JI)On$ivv>YCP{#RHdAW{jLp~ zb;dHOwk@Q^s;F@RLZ1JZYWIZWz*LPyX=QQdqsA#S+X^f z=E)sStBn1YK%ruP`c=aF+1(qnQoo$!&4kcH`V7f^1dloCo`vGV>-Rk%?kuE}=rma_ zO$MLX=ewvuD=EBEA%+%p*;+_aq_iMRqg@2q>hZa}62<&BaEe&OEpiz*PN$*2=wA{} zvkrEUHLc*04BZ(okH8@13wnBeA##h)QZgR094C0mJxn5wm`$#$~1_ns)TaK zDfU;<(WGO!wB5d#MlxR*LYQw6nP4;4u7d>Tw$Ph~wn7Xx3J9)7V<*?~?QX7_8>{O9 zB4S_iG4X1s&I+erZe`vMZL;AhdPLgQh3yl{MzbvXIg~fC=h*=LD7^A5tHtnAKTd3e z^!Rn~o$I*{+W~!fC4*jrXGCVu4W z{)}*(@N*aRKipjJsPJ(J3VJLYN z#LcToh|D|GfyY|N6UmE;7mQMDrBx!?9>6zFDBH1jGt|m(tJpW8EWz6obPn=cC%$<_ zc@lG<(ClAy@Np_m@ph^MPqu>BDl_~&#mysGLpIsVI&H)9cI8nKTk{+A-cW+rKEe;+ z>1$Alo2qzDW&xhL4pC2r^17LFY2LFAgfv8PM~ElUxTQFS@u80Ix_Jw}?1NR<66QYh zSn3vFzJ(IU@Q_b?f_xfwiP3A{5`h^XJxo5YhF$@Kt!65nE5}fnCm-oyy=)bG#+==J z!2`ikptDB-DQr1BKf;~lJ(*6j2+k5mN&+&empVyqZ_${ll1~bXs=r(v4Wl}S~+(Nl}`J|V^FjpcD{BD#tV^3bGl@;$40~tf}kcH&h zP&XfyN)7jP^Cs!d_4vnbzBL_hUY>Y-#s9@m*3RS$5P8og{QFW~AzT3u9_;4#-XFp> zSsoW@R{ z))A$-2bui{$zuf9L;7xF?mj}}L;5L_KO}e`(9@}#*!Qe58pPplZrCN0%jA6tN2g#V zzVr!^0kL0w#d?dfd+C3W8D!6QEE3;~Z993D>)~p28AQ@V9hIe8Q_~bhN~efO6?6ES zo03Zn^Hn(E10N{(T#&zLmEwkCHe`mzwkujE*>H@BJ3Auc)$yoCR?<~gD!=h3>%mpx ztI5QoLa*DsjEYN^LVT_l(|4|ZN5;TLKHUL$ubp`)(vz?{p zOp;$u_NQn=$u#U-yb&&G=6kmjU`WE4Z!%wgK=>iyM})nE($`$uJsu32{cq%5sOpe{ ny?Es!EF*gyI3GWYT>a;6>d>XnTkGI-nTubPg{2~7?bP~j0{QAd diff --git a/dll/dxwnd.vs2008.vcproj b/dll/dxwnd.vs2008.vcproj index 1ab5fc5..9115aa3 100644 --- a/dll/dxwnd.vs2008.vcproj +++ b/dll/dxwnd.vs2008.vcproj @@ -445,6 +445,10 @@ RelativePath=".\msghook.cpp" > + + @@ -457,6 +461,10 @@ RelativePath=".\opengl.cpp" > + + @@ -526,6 +534,10 @@ RelativePath=".\resource.h" > + + diff --git a/dll/gdi32.cpp b/dll/gdi32.cpp index e48a5b2..4c9c8d3 100644 --- a/dll/gdi32.cpp +++ b/dll/gdi32.cpp @@ -6,9 +6,12 @@ #include "hddraw.h" #include "dxhook.h" #include "dxhelper.h" +#include "shareddc.hpp" #include "stdio.h" +static BOOL bGDIRecursionFlag = FALSE; + static void Stopper(char *s, int line) { char sMsg[81]; @@ -19,7 +22,7 @@ static void Stopper(char *s, int line) //#define STOPPER_TEST // comment out to eliminate #ifdef STOPPER_TEST #define STOPPER(s) Stopper(s, __LINE__) -#else +#elsedxw #define STOPPER(s) #endif @@ -29,6 +32,8 @@ ResizePalette_Type pResizePalette = NULL; BOOL WINAPI extResizePalette(HPALETTE, UINT); #endif +#define _Warn(s) MessageBox(0, s, "to do", MB_ICONEXCLAMATION) + /* typedef COLORREF (WINAPI *SetBkColor_Type)(HDC, COLORREF); typedef COLORREF (WINAPI *SetTextColor_Type)(HDC hdc, COLORREF crColor); @@ -45,6 +50,81 @@ int WINAPI extSetBkMode(HDC, int); typedef int (WINAPI *SetDIBits_Type)(HDC, HBITMAP, UINT, UINT, const VOID *, const BITMAPINFO *, UINT); int WINAPI extSetDIBits(HDC, HBITMAP, UINT, UINT, const VOID *, const BITMAPINFO *, UINT); SetDIBits_Type pSetDIBits = NULL; +typedef int (WINAPI *OffsetRgn_Type)(HRGN, int, int); +OffsetRgn_Type pOffsetRgn = NULL; +int WINAPI extOffsetRgn(HRGN, int, int); +typedef COLORREF (WINAPI *GetPixel_Type)(HDC, int, int); +GetPixel_Type pGetPixel = NULL; +COLORREF WINAPI extGetPixel(HDC, int, int); +typedef BOOL (WINAPI *PlgBlt_Type)(HDC, const POINT *, HDC, int, int, int, int, HBITMAP, int, int); +PlgBlt_Type pPlgBlt = NULL; +BOOL WINAPI extPlgBlt(HDC, const POINT *, HDC, int, int, int, int, HBITMAP, int, int); +typedef BOOL (WINAPI *SetPixelV_Type)(HDC, int, int, COLORREF); +SetPixelV_Type pSetPixelV = NULL; +BOOL WINAPI extSetPixelV(HDC, int, int, COLORREF); +typedef BOOL (WINAPI *Chord_Type)(HDC, int, int, int, int, int, int, int, int); +Chord_Type pChord = NULL; +BOOL WINAPI extChord(HDC, int, int, int, int, int, int, int, int); +typedef BOOL (WINAPI *PolyTextOutA_Type)(HDC, const POLYTEXTA *, int); +PolyTextOutA_Type pPolyTextOutA = NULL; +BOOL WINAPI extPolyTextOutA(HDC, const POLYTEXTA *, int); +typedef BOOL (WINAPI *PolyTextOutW_Type)(HDC, const POLYTEXTW *, int); +PolyTextOutW_Type pPolyTextOutW = NULL; +BOOL WINAPI extPolyTextOutW(HDC, const POLYTEXTW *, int); +typedef int (WINAPI *GetDIBits_Type)(HDC, HBITMAP, UINT, UINT, LPVOID, LPBITMAPINFO, UINT); +GetDIBits_Type pGetDIBits = NULL; +int WINAPI extGetDIBits(HDC, HBITMAP, UINT, UINT, LPVOID, LPBITMAPINFO, UINT); +typedef HBITMAP (WINAPI *CreateDIBitmap_Type)(HDC, BITMAPINFOHEADER *, DWORD, const VOID *, const BITMAPINFO *, UINT); +CreateDIBitmap_Type pCreateDIBitmap = NULL; +HBITMAP WINAPI extCreateDIBitmap(HDC, BITMAPINFOHEADER *, DWORD, const VOID *, const BITMAPINFO *, UINT); +typedef HBITMAP (WINAPI *CreateDIBSection_Type)(HDC, const BITMAPINFO *, UINT, VOID **, HANDLE, DWORD); +CreateDIBSection_Type pCreateDIBSection = NULL; +HBITMAP WINAPI extCreateDIBSection(HDC, const BITMAPINFO *, UINT, VOID **, HANDLE, DWORD); +typedef HBITMAP (WINAPI *CreateDiscardableBitmap_Type)(HDC, int, int); +CreateDiscardableBitmap_Type pCreateDiscardableBitmap = NULL; +HBITMAP WINAPI extCreateDiscardableBitmap(HDC, int, int); +typedef BOOL (WINAPI *ExtFloodFill_Type)(HDC, int, int, COLORREF, UINT); +ExtFloodFill_Type pExtFloodFill = NULL; +BOOL WINAPI extExtFloodFill(HDC, int, int, COLORREF, UINT); +typedef BOOL (WINAPI *GdiAlphaBlend_Type)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION); +GdiAlphaBlend_Type pGdiAlphaBlend = NULL; +BOOL WINAPI extGdiAlphaBlend(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION); +typedef BOOL (WINAPI *GdiGradientFill_Type)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG); +GdiGradientFill_Type pGdiGradientFill = NULL; +BOOL WINAPI extGdiGradientFill(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG); +typedef BOOL (WINAPI *GdiTransparentBlt_Type)(HDC, int, int, int, int, HDC, int, int, int, int, UINT); +GdiTransparentBlt_Type pGdiTransparentBlt = NULL; +BOOL WINAPI extGdiTransparentBlt(HDC, int, int, int, int, HDC, int, int, int, int, UINT); +typedef BOOL (WINAPI *Pie_Type)(HDC, int, int, int, int, int, int, int, int); +Pie_Type pPie = NULL; +BOOL WINAPI extPie(HDC, int, int, int, int, int, int, int, int); +typedef BOOL (WINAPI *AngleArc_Type)(HDC, int, int, DWORD, FLOAT, FLOAT); +AngleArc_Type pAngleArc = NULL; +BOOL WINAPI extAngleArc(HDC, int, int, DWORD, FLOAT, FLOAT); +typedef BOOL (WINAPI *PolyPolyline_Type)(HDC, const POINT *, const DWORD *, DWORD); +PolyPolyline_Type pPolyPolyline = NULL; +BOOL WINAPI extPolyPolyline(HDC, const POINT *, const DWORD *, DWORD); +typedef BOOL (WINAPI *FillRgn_Type)(HDC, HRGN, HBRUSH); +FillRgn_Type pFillRgn = NULL; +BOOL WINAPI extFillRgn(HDC, HRGN, HBRUSH); +typedef BOOL (WINAPI *FrameRgn_Type)(HDC, HRGN, HBRUSH, int, int); +FrameRgn_Type pFrameRgn = NULL; +BOOL WINAPI extFrameRgn(HDC, HRGN, HBRUSH, int, int); +typedef BOOL (WINAPI *InvertRgn_Type)(HDC, HRGN); +InvertRgn_Type pInvertRgn = NULL; +BOOL WINAPI extInvertRgn(HDC, HRGN); +typedef BOOL (WINAPI *PaintRgn_Type)(HDC, HRGN); +PaintRgn_Type pPaintRgn = NULL; +BOOL WINAPI extPaintRgn(HDC, HRGN); +typedef int (WINAPI *SetMapMode_Type)(HDC, int); +SetMapMode_Type pSetMapMode = NULL; +int WINAPI extSetMapMode(HDC, int); +typedef BOOL (WINAPI *RoundRect_Type)(HDC, int, int, int, int, int, int); +RoundRect_Type pRoundRect = NULL; +BOOL WINAPI extRoundRect(HDC, int, int, int, int, int, int); +typedef BOOL (WINAPI *PolyPolygon_Type)(HDC, const POINT *, const INT *, int); +PolyPolygon_Type pPolyPolygon = NULL; +BOOL WINAPI extPolyPolygon(HDC, const POINT *, const INT *, int); static HookEntry_Type Hooks[]={ @@ -58,87 +138,109 @@ static HookEntry_Type Hooks[]={ {HOOK_HOT_CANDIDATE, "RealizePalette", (FARPROC)RealizePalette, (FARPROC *)&pGDIRealizePalette, (FARPROC)extRealizePalette}, {HOOK_HOT_CANDIDATE, "GetSystemPaletteEntries", (FARPROC)GetSystemPaletteEntries, (FARPROC *)&pGDIGetSystemPaletteEntries, (FARPROC)extGetSystemPaletteEntries}, {HOOK_HOT_CANDIDATE, "SetSystemPaletteUse", (FARPROC)SetSystemPaletteUse, (FARPROC *)&pSetSystemPaletteUse, (FARPROC)extSetSystemPaletteUse}, - {HOOK_IAT_CANDIDATE, "StretchDIBits", (FARPROC)StretchDIBits, (FARPROC *)&pStretchDIBits, (FARPROC)extStretchDIBits}, - //{HOOK_IAT_CANDIDATE, "CreateCompatibleBitmap", (FARPROC)NULL, (FARPROC *)&pCreateCompatibleBitmap, (FARPROC)extCreateCompatibleBitmap}, - //{HOOK_IAT_CANDIDATE, "SetMapMode", (FARPROC)NULL, (FARPROC *)NULL, (FARPROC)extSetMapMode}, {HOOK_IAT_CANDIDATE, "SetPixelFormat", (FARPROC)NULL, (FARPROC *)&pGDISetPixelFormat, (FARPROC)extGDISetPixelFormat}, {HOOK_IAT_CANDIDATE, "GetPixelFormat", (FARPROC)NULL, (FARPROC *)&pGDIGetPixelFormat, (FARPROC)extGDIGetPixelFormat}, {HOOK_IAT_CANDIDATE, "ChoosePixelFormat", (FARPROC)NULL, (FARPROC *)&pChoosePixelFormat, (FARPROC)extChoosePixelFormat}, {HOOK_IAT_CANDIDATE, "DescribePixelFormat", (FARPROC)NULL, (FARPROC *)&pDescribePixelFormat, (FARPROC)extDescribePixelFormat}, {HOOK_HOT_CANDIDATE, "GetPaletteEntries", (FARPROC)GetPaletteEntries, (FARPROC *)&pGetPaletteEntries, (FARPROC)extGetPaletteEntries}, {HOOK_HOT_CANDIDATE, "GetSystemPaletteUse", (FARPROC)GetSystemPaletteUse, (FARPROC *)&pGetSystemPaletteUse, (FARPROC)extGetSystemPaletteUse}, + {HOOK_HOT_CANDIDATE, "CreateICA", (FARPROC)CreateICA, (FARPROC *)&pCreateICA, (FARPROC)extCreateICA}, // Riven #ifdef TRACEPALETTE {HOOK_IAT_CANDIDATE, "ResizePalette", (FARPROC)ResizePalette, (FARPROC *)&pResizePalette, (FARPROC)extResizePalette}, -#endif - {HOOK_HOT_CANDIDATE, "CreateICA", (FARPROC)CreateICA, (FARPROC *)&pCreateICA, (FARPROC)extCreateICA}, // Riven +#endif {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator }; - + static HookEntry_Type RemapHooks[]={ {HOOK_IAT_CANDIDATE, "SetViewportOrgEx", (FARPROC)SetViewportOrgEx, (FARPROC *)&pSetViewportOrgEx, (FARPROC)extSetViewportOrgEx}, // needed in ShowBanner - {HOOK_IAT_CANDIDATE, "SetViewportExtEx", (FARPROC)NULL, (FARPROC *)&pSetViewportExtEx, (FARPROC)extSetViewportExtEx}, - {HOOK_IAT_CANDIDATE, "GetViewportOrgEx", (FARPROC)NULL, (FARPROC *)&pGetViewportOrgEx, (FARPROC)extGetViewportOrgEx}, - {HOOK_IAT_CANDIDATE, "GetViewportExtEx", (FARPROC)NULL, (FARPROC *)&pGetViewportExtEx, (FARPROC)extGetViewportExtEx}, - {HOOK_IAT_CANDIDATE, "GetWindowOrgEx", (FARPROC)NULL, (FARPROC *)&pGetWindowOrgEx, (FARPROC)extGetWindowOrgEx}, - {HOOK_IAT_CANDIDATE, "SetWindowOrgEx", (FARPROC)NULL, (FARPROC *)&pSetWindowOrgEx, (FARPROC)extSetWindowOrgEx}, - {HOOK_IAT_CANDIDATE, "GetCurrentPositionEx", (FARPROC)NULL, (FARPROC *)&pGetCurrentPositionEx, (FARPROC)extGetCurrentPositionEx}, - {HOOK_IAT_CANDIDATE, "SetDIBitsToDevice", (FARPROC)NULL, (FARPROC *)&pSetDIBitsToDevice, (FARPROC)extSetDIBitsToDevice}, // does the stretching - {HOOK_IAT_CANDIDATE, "GetRgnBox", (FARPROC)NULL, (FARPROC *)&pGetRgnBox, (FARPROC)extGetRgnBox}, + {HOOK_IAT_CANDIDATE, "SetViewportExtEx", (FARPROC)SetViewportExtEx, (FARPROC *)&pSetViewportExtEx, (FARPROC)extSetViewportExtEx}, + {HOOK_IAT_CANDIDATE, "GetViewportOrgEx", (FARPROC)GetViewportOrgEx, (FARPROC *)&pGetViewportOrgEx, (FARPROC)extGetViewportOrgEx}, + {HOOK_IAT_CANDIDATE, "GetViewportExtEx", (FARPROC)GetViewportExtEx, (FARPROC *)&pGetViewportExtEx, (FARPROC)extGetViewportExtEx}, + {HOOK_IAT_CANDIDATE, "GetWindowOrgEx", (FARPROC)GetWindowOrgEx, (FARPROC *)&pGetWindowOrgEx, (FARPROC)extGetWindowOrgEx}, + {HOOK_IAT_CANDIDATE, "SetWindowOrgEx", (FARPROC)SetWindowOrgEx, (FARPROC *)&pSetWindowOrgEx, (FARPROC)extSetWindowOrgEx}, + {HOOK_IAT_CANDIDATE, "GetCurrentPositionEx", (FARPROC)GetCurrentPositionEx, (FARPROC *)&pGetCurrentPositionEx, (FARPROC)extGetCurrentPositionEx}, + {HOOK_IAT_CANDIDATE, "GetRgnBox", (FARPROC)GetRgnBox, (FARPROC *)&pGetRgnBox, (FARPROC)extGetRgnBox}, //{HOOK_IAT_CANDIDATE, "GetRegionData", (FARPROC)NULL, (FARPROC *)&pGetRegionData, (FARPROC)extGetRegionData}, - //{HOOK_HOT_CANDIDATE, "SetDIBits", (FARPROC)SetDIBits, (FARPROC *)&pSetDIBits, (FARPROC)extSetDIBits}, + {HOOK_IAT_CANDIDATE, "CreateCompatibleDC", (FARPROC)CreateCompatibleDC, (FARPROC *)&pGDICreateCompatibleDC, (FARPROC)extGDICreateCompatibleDC}, /* to check */ + //TODO {HOOK_IAT_CANDIDATE, "DrawEscape", (FARPROC)DrawEscape, (FARPROC *)&pDrawEscape, (FARPROC)extDrawEscape}, /* to check */ {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator }; -static HookEntry_Type ScaledHooks[]={ - {HOOK_IAT_CANDIDATE, "Rectangle", (FARPROC)Rectangle, (FARPROC *)&pGDIRectangle, (FARPROC)extRectangle}, - {HOOK_IAT_CANDIDATE, "TextOutA", (FARPROC)TextOutA, (FARPROC *)&pGDITextOutA, (FARPROC)extTextOutA}, - {HOOK_IAT_CANDIDATE, "GetClipBox", (FARPROC)NULL, (FARPROC *)&pGDIGetClipBox, (FARPROC)extGetClipBox}, - {HOOK_IAT_CANDIDATE, "IntersectClipRect", (FARPROC)IntersectClipRect, (FARPROC *)&pIntersectClipRect, (FARPROC)extIntersectClipRect}, // Riven !! - //{HOOK_IAT_CANDIDATE, "GetRgnBox", (FARPROC)NULL, (FARPROC *)&pGetRgnBox, (FARPROC)extGetRgnBox}, - {HOOK_IAT_CANDIDATE, "Polyline", (FARPROC)NULL, (FARPROC *)&pPolyline, (FARPROC)extPolyline}, - {HOOK_IAT_CANDIDATE, "PolyBezierTo", (FARPROC)NULL, (FARPROC *)&pPolyBezierTo, (FARPROC)extPolyBezierTo}, - {HOOK_IAT_CANDIDATE, "PolylineTo", (FARPROC)NULL, (FARPROC *)&pPolylineTo, (FARPROC)extPolylineTo}, - {HOOK_IAT_CANDIDATE, "PolyDraw", (FARPROC)NULL, (FARPROC *)&pPolyDraw, (FARPROC)extPolyDraw}, - {HOOK_IAT_CANDIDATE, "MoveToEx", (FARPROC)NULL, (FARPROC *)&pMoveToEx, (FARPROC)extMoveToEx}, - {HOOK_IAT_CANDIDATE, "ArcTo", (FARPROC)NULL, (FARPROC *)&pArcTo, (FARPROC)extArcTo}, - {HOOK_IAT_CANDIDATE, "LineTo", (FARPROC)NULL, (FARPROC *)&pLineTo, (FARPROC)extLineTo}, - {HOOK_IAT_CANDIDATE, "SetPixel", (FARPROC)NULL, (FARPROC *)&pSetPixel, (FARPROC)extSetPixel}, - {HOOK_IAT_CANDIDATE, "Ellipse", (FARPROC)NULL, (FARPROC *)&pEllipse, (FARPROC)extEllipse}, - {HOOK_IAT_CANDIDATE, "Polygon", (FARPROC)NULL, (FARPROC *)&pPolygon, (FARPROC)extPolygon}, - {HOOK_IAT_CANDIDATE, "Arc", (FARPROC)NULL, (FARPROC *)&pArc, (FARPROC)extArc}, - // commented out since they alter text on screen...... (see Imperialism II difficulty level menu) - // v2.03.47 - restored: needed for "688(I) Hunter Killer" periscope .... - {HOOK_IAT_CANDIDATE, "CreateEllipticRgn", (FARPROC)NULL, (FARPROC *)&pCreateEllipticRgn, (FARPROC)extCreateEllipticRgn}, - {HOOK_IAT_CANDIDATE, "CreateEllipticRgnIndirect", (FARPROC)NULL, (FARPROC *)&pCreateEllipticRgnIndirect, (FARPROC)extCreateEllipticRgnIndirect}, - // CreateRectRgn must be hooked in scaled mode to let Avernum work correctly! - {HOOK_IAT_CANDIDATE, "CreateRectRgn", (FARPROC)NULL, (FARPROC *)&pCreateRectRgn, (FARPROC)extCreateRectRgn}, - {HOOK_IAT_CANDIDATE, "CreateRectRgnIndirect", (FARPROC)NULL, (FARPROC *)&pCreateRectRgnIndirect, (FARPROC)extCreateRectRgnIndirect}, - //{HOOK_IAT_CANDIDATE, "CreatePolygonRgn", (FARPROC)NULL, (FARPROC *)&pCreatePolygonRgn, (FARPROC)extCreatePolygonRgn}, - // same as emulated GDI ... - {HOOK_IAT_CANDIDATE, "CreateCompatibleDC", (FARPROC)CreateCompatibleDC, (FARPROC *)&pGDICreateCompatibleDC, (FARPROC)extGDICreateCompatibleDC}, - {HOOK_IAT_CANDIDATE, "DeleteDC", (FARPROC)DeleteDC, (FARPROC *)&pGDIDeleteDC, (FARPROC)extGDIDeleteDC}, - {HOOK_IAT_CANDIDATE, "CreateDCA", (FARPROC)CreateDCA, (FARPROC *)&pGDICreateDC, (FARPROC)extGDICreateDC}, - // CreateDCW ..... +static HookEntry_Type SyscallHooks[]={ + {HOOK_IAT_CANDIDATE, "StretchDIBits", (FARPROC)StretchDIBits, (FARPROC *)&pStretchDIBits, (FARPROC)extStretchDIBits}, + {HOOK_HOT_CANDIDATE, "SetDIBits", (FARPROC)SetDIBits, (FARPROC *)&pSetDIBits, (FARPROC)extSetDIBits}, + {HOOK_HOT_CANDIDATE, "GetDIBits", (FARPROC)GetDIBits, (FARPROC *)&pGetDIBits, (FARPROC)extGetDIBits}, + {HOOK_IAT_CANDIDATE, "CreateCompatibleBitmap", (FARPROC)CreateCompatibleBitmap, (FARPROC *)&pCreateCompatibleBitmap, (FARPROC)extCreateCompatibleBitmap}, + {HOOK_IAT_CANDIDATE, "CreateDIBitmap", (FARPROC)NULL, (FARPROC *)&pCreateDIBitmap, (FARPROC)extCreateDIBitmap}, + {HOOK_IAT_CANDIDATE, "CreateDIBSection", (FARPROC)NULL, (FARPROC *)&pCreateDIBSection, (FARPROC)extCreateDIBSection}, + {HOOK_IAT_CANDIDATE, "CreateDiscardableBitmap", (FARPROC)NULL, (FARPROC *)&pCreateDiscardableBitmap, (FARPROC)extCreateDiscardableBitmap}, + {HOOK_IAT_CANDIDATE, "ExtFloodFill", (FARPROC)NULL, (FARPROC *)&pExtFloodFill, (FARPROC)extExtFloodFill}, + {HOOK_IAT_CANDIDATE, "GdiAlphaBlend", (FARPROC)NULL, (FARPROC *)&pGdiAlphaBlend, (FARPROC)extGdiAlphaBlend}, + {HOOK_IAT_CANDIDATE, "GdiGradientFill", (FARPROC)NULL, (FARPROC *)&pGdiGradientFill, (FARPROC)extGdiGradientFill}, + {HOOK_IAT_CANDIDATE, "GdiTransparentBlt", (FARPROC)NULL, (FARPROC *)&pGdiTransparentBlt, (FARPROC)extGdiTransparentBlt}, + {HOOK_IAT_CANDIDATE, "Pie", (FARPROC)NULL, (FARPROC *)&pPie, (FARPROC)extPie}, + {HOOK_IAT_CANDIDATE, "AngleArc", (FARPROC)NULL, (FARPROC *)&pAngleArc, (FARPROC)extAngleArc}, + {HOOK_IAT_CANDIDATE, "PolyPolyline", (FARPROC)NULL, (FARPROC *)&pPolyPolyline, (FARPROC)extPolyPolyline}, + {HOOK_IAT_CANDIDATE, "FillRgn", (FARPROC)NULL, (FARPROC *)&pFillRgn, (FARPROC)extFillRgn}, + {HOOK_IAT_CANDIDATE, "FrameRgn", (FARPROC)NULL, (FARPROC *)&pFrameRgn, (FARPROC)extFrameRgn}, + {HOOK_IAT_CANDIDATE, "InvertRgn", (FARPROC)NULL, (FARPROC *)&pInvertRgn, (FARPROC)extInvertRgn}, + {HOOK_IAT_CANDIDATE, "PaintRgn", (FARPROC)NULL, (FARPROC *)&pPaintRgn, (FARPROC)extPaintRgn}, + //{HOOK_IAT_CANDIDATE, "SetMapMode", (FARPROC)NULL, (FARPROC *)NULL, (FARPROC)extSetMapMode}, // crashes ??? + {HOOK_IAT_CANDIDATE, "SetDIBitsToDevice", (FARPROC)SetDIBitsToDevice, (FARPROC *)&pSetDIBitsToDevice, (FARPROC)extSetDIBitsToDevice}, // does the stretching + {HOOK_IAT_CANDIDATE, "Polyline", (FARPROC)Polyline, (FARPROC *)&pPolyline, (FARPROC)extPolyline}, {HOOK_IAT_CANDIDATE, "BitBlt", (FARPROC)BitBlt, (FARPROC *)&pGDIBitBlt, (FARPROC)extGDIBitBlt}, {HOOK_IAT_CANDIDATE, "StretchBlt", (FARPROC)StretchBlt, (FARPROC *)&pGDIStretchBlt, (FARPROC)extGDIStretchBlt}, {HOOK_IAT_CANDIDATE, "PatBlt", (FARPROC)PatBlt, (FARPROC *)&pGDIPatBlt, (FARPROC)extGDIPatBlt}, - {HOOK_IAT_CANDIDATE, "MaskBlt", (FARPROC)NULL, (FARPROC *)&pMaskBlt, (FARPROC)extMaskBlt}, + {HOOK_IAT_CANDIDATE, "MaskBlt", (FARPROC)MaskBlt, (FARPROC *)&pMaskBlt, (FARPROC)extMaskBlt}, + {HOOK_IAT_CANDIDATE, "TextOutA", (FARPROC)TextOutA, (FARPROC *)&pGDITextOutA, (FARPROC)extTextOutA}, + {HOOK_IAT_CANDIDATE, "TextOutW", (FARPROC)TextOutW, (FARPROC *)&pGDITextOutW, (FARPROC)extTextOutW}, + {HOOK_IAT_CANDIDATE, "Rectangle", (FARPROC)Rectangle, (FARPROC *)&pGDIRectangle, (FARPROC)extRectangle}, + {HOOK_IAT_CANDIDATE, "RoundRect", (FARPROC)RoundRect, (FARPROC *)&pRoundRect, (FARPROC)extRoundRect}, + {HOOK_IAT_CANDIDATE, "Polygon", (FARPROC)Polygon, (FARPROC *)&pPolygon, (FARPROC)extPolygon}, + {HOOK_IAT_CANDIDATE, "PolyPolygon", (FARPROC)PolyPolygon, (FARPROC *)&pPolyPolygon, (FARPROC)extPolyPolygon}, + {HOOK_IAT_CANDIDATE, "PolyBezier", (FARPROC)PolyBezier, (FARPROC *)&pPolyBezier, (FARPROC)extPolyBezier}, + {HOOK_IAT_CANDIDATE, "PolyBezierTo", (FARPROC)PolyBezierTo, (FARPROC *)&pPolyBezierTo, (FARPROC)extPolyBezierTo}, + {HOOK_IAT_CANDIDATE, "PolylineTo", (FARPROC)PolylineTo, (FARPROC *)&pPolylineTo, (FARPROC)extPolylineTo}, + {HOOK_IAT_CANDIDATE, "PolyDraw", (FARPROC)PolyDraw, (FARPROC *)&pPolyDraw, (FARPROC)extPolyDraw}, + {HOOK_IAT_CANDIDATE, "GetPixel", (FARPROC)GetPixel, (FARPROC *)&pGetPixel, (FARPROC)extGetPixel}, + {HOOK_IAT_CANDIDATE, "PlgBlt", (FARPROC)PlgBlt, (FARPROC *)&pPlgBlt, (FARPROC)extPlgBlt}, + {HOOK_IAT_CANDIDATE, "SetPixel", (FARPROC)SetPixel, (FARPROC *)&pSetPixel, (FARPROC)extSetPixel}, + {HOOK_IAT_CANDIDATE, "SetPixelV", (FARPROC)SetPixelV, (FARPROC *)&pSetPixelV, (FARPROC)extSetPixelV}, + {HOOK_IAT_CANDIDATE, "Chord", (FARPROC)Chord, (FARPROC *)&pChord, (FARPROC)extChord}, + {HOOK_IAT_CANDIDATE, "Ellipse", (FARPROC)Ellipse, (FARPROC *)&pEllipse, (FARPROC)extEllipse}, {HOOK_IAT_CANDIDATE, "ExtTextOutA", (FARPROC)ExtTextOutA, (FARPROC *)&pExtTextOutA, (FARPROC)extExtTextOutA}, {HOOK_IAT_CANDIDATE, "ExtTextOutW", (FARPROC)ExtTextOutW, (FARPROC *)&pExtTextOutW, (FARPROC)extExtTextOutW}, + {HOOK_IAT_CANDIDATE, "PolyTextOutA", (FARPROC)PolyTextOutA, (FARPROC *)&pPolyTextOutA, (FARPROC)extPolyTextOutA}, + {HOOK_IAT_CANDIDATE, "PolyTextOutW", (FARPROC)PolyTextOutA, (FARPROC *)&pPolyTextOutA, (FARPROC)extPolyTextOutA}, + {HOOK_IAT_CANDIDATE, "ArcTo", (FARPROC)ArcTo, (FARPROC *)&pArcTo, (FARPROC)extArcTo}, + {HOOK_IAT_CANDIDATE, "LineTo", (FARPROC)LineTo, (FARPROC *)&pLineTo, (FARPROC)extLineTo}, + {HOOK_IAT_CANDIDATE, "Arc", (FARPROC)Arc, (FARPROC *)&pArc, (FARPROC)extArc}, + {HOOK_IAT_CANDIDATE, "MoveToEx", (FARPROC)MoveToEx, (FARPROC *)&pMoveToEx, (FARPROC)extMoveToEx}, + {HOOK_IAT_CANDIDATE, "GetClipBox", (FARPROC)GetClipBox, (FARPROC *)&pGDIGetClipBox, (FARPROC)extGetClipBox}, + {HOOK_IAT_CANDIDATE, "IntersectClipRect", (FARPROC)IntersectClipRect, (FARPROC *)&pIntersectClipRect, (FARPROC)extIntersectClipRect}, // Riven !! + {HOOK_IAT_CANDIDATE, "DeleteDC", (FARPROC)DeleteDC, (FARPROC *)&pGDIDeleteDC, (FARPROC)extGDIDeleteDC}, // for tracing only! + {HOOK_IAT_CANDIDATE, "CreateDCA", (FARPROC)CreateDCA, (FARPROC *)&pGDICreateDCA, (FARPROC)extGDICreateDCA}, + {HOOK_IAT_CANDIDATE, "CreateDCW", (FARPROC)CreateDCW, (FARPROC *)&pGDICreateDCW, (FARPROC)extGDICreateDCW}, + // CreateDCW ..... {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator +}; + +static HookEntry_Type ScaledHooks[]={ + // commented out since they alter text on screen...... (see Imperialism II difficulty level menu) + // v2.03.47 - restored: needed for "688(I) Hunter Killer" periscope .... + {HOOK_IAT_CANDIDATE, "CreateEllipticRgn", (FARPROC)CreateEllipticRgn, (FARPROC *)&pCreateEllipticRgn, (FARPROC)extCreateEllipticRgn}, + {HOOK_IAT_CANDIDATE, "CreateEllipticRgnIndirect", (FARPROC)CreateEllipticRgnIndirect, (FARPROC *)&pCreateEllipticRgnIndirect, (FARPROC)extCreateEllipticRgnIndirect}, + // CreateRectRgn must be hooked in scaled mode to let Avernum work correctly! + {HOOK_IAT_CANDIDATE, "CreateRectRgn", (FARPROC)CreateRectRgn, (FARPROC *)&pCreateRectRgn, (FARPROC)extCreateRectRgn}, + {HOOK_IAT_CANDIDATE, "CreateRectRgnIndirect", (FARPROC)CreateRectRgnIndirect, (FARPROC *)&pCreateRectRgnIndirect, (FARPROC)extCreateRectRgnIndirect}, + {HOOK_IAT_CANDIDATE, "CreatePolygonRgn", (FARPROC)CreatePolygonRgn, (FARPROC *)&pCreatePolygonRgn, (FARPROC)extCreatePolygonRgn}, + // same as emulated GDI ... + {HOOK_IAT_CANDIDATE, "SetRectRgn", (FARPROC)SetRectRgn, (FARPROC *)&pSetRectRgn, (FARPROC)extSetRectRgn}, {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator }; static HookEntry_Type EmulateHooks[]={ - // useless CreateCompatibleDC: it maps VirtualHDC on top of VirtualHDC, then does nothing, unless when asked to operate on 0!.... - //{HOOK_IAT_CANDIDATE, "CreateCompatibleDC", (FARPROC)CreateCompatibleDC, (FARPROC *)&pGDICreateCompatibleDC, (FARPROC)extEMUCreateCompatibleDC}, - // useless DeleteDC: it's just a proxy - //{HOOK_IAT_CANDIDATE, "DeleteDC", (FARPROC)DeleteDC, (FARPROC *)&pGDIDeleteDC, (FARPROC)extGDIDeleteDC}, - {HOOK_IAT_CANDIDATE, "CreateDCA", (FARPROC)CreateDCA, (FARPROC *)&pGDICreateDC, (FARPROC)extGDICreateDC}, - // CreateDCW ..... - {HOOK_IAT_CANDIDATE, "GetObjectType", (FARPROC)GetObjectType, (FARPROC *)&pGetObjectType, (FARPROC)extGetObjectType}, - {HOOK_IAT_CANDIDATE, "GetClipBox", (FARPROC)NULL, (FARPROC *)&pGDIGetClipBox, (FARPROC)extGetClipBox}, {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator }; @@ -155,10 +257,10 @@ static HookEntry_Type GammaHooks[]={ }; static HookEntry_Type FontHooks[]={ - {HOOK_IAT_CANDIDATE, "CreateScalableFontResourceA", (FARPROC)NULL, (FARPROC *)&pCreateScalableFontResourceA, (FARPROC)extCreateScalableFontResourceA}, - {HOOK_IAT_CANDIDATE, "CreateScalableFontResourceW", (FARPROC)NULL, (FARPROC *)&pCreateScalableFontResourceW, (FARPROC)extCreateScalableFontResourceW}, - {HOOK_IAT_CANDIDATE, "AddFontResourceA", (FARPROC)NULL, (FARPROC *)&pAddFontResourceA, (FARPROC)extAddFontResourceA}, - {HOOK_IAT_CANDIDATE, "AddFontResourceW", (FARPROC)NULL, (FARPROC *)&pAddFontResourceW, (FARPROC)extAddFontResourceW}, + {HOOK_IAT_CANDIDATE, "CreateScalableFontResourceA", (FARPROC)CreateScalableFontResourceA, (FARPROC *)&pCreateScalableFontResourceA, (FARPROC)extCreateScalableFontResourceA}, + {HOOK_IAT_CANDIDATE, "CreateScalableFontResourceW", (FARPROC)CreateScalableFontResourceW, (FARPROC *)&pCreateScalableFontResourceW, (FARPROC)extCreateScalableFontResourceW}, + {HOOK_IAT_CANDIDATE, "AddFontResourceA", (FARPROC)AddFontResourceA, (FARPROC *)&pAddFontResourceA, (FARPROC)extAddFontResourceA}, + {HOOK_IAT_CANDIDATE, "AddFontResourceW", (FARPROC)AddFontResourceW, (FARPROC *)&pAddFontResourceW, (FARPROC)extAddFontResourceW}, {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator }; @@ -181,6 +283,7 @@ void HookGDI32Init() HookLibInit(Hooks); HookLibInit(RemapHooks); HookLibInit(ScaledHooks); + HookLibInit(SyscallHooks); HookLibInit(EmulateHooks); HookLibInit(TextHooks); HookLibInit(GammaHooks); @@ -191,6 +294,7 @@ void HookGDI32(HMODULE module) { HookLibrary(module, Hooks, libname); + if (dxw.GDIEmulationMode != GDIMODE_NONE) HookLibrary(module, SyscallHooks, libname); if (dxw.dwFlags1 & CLIENTREMAPPING) HookLibrary(module, RemapHooks, libname); if (dxw.dwFlags2 & GDISTRETCHED) HookLibrary(module, ScaledHooks, libname); if (dxw.dwFlags3 & GDIEMULATEDC) HookLibrary(module, EmulateHooks, libname); @@ -207,6 +311,7 @@ FARPROC Remap_GDI32_ProcAddress(LPCSTR proc, HMODULE hModule) if(addr=RemapLibrary(proc, hModule, Hooks)) return addr; + if (dxw.GDIEmulationMode != GDIMODE_NONE) if(addr=RemapLibrary(proc, hModule, SyscallHooks)) return addr; if (dxw.dwFlags1 & CLIENTREMAPPING) if(addr=RemapLibrary(proc, hModule, RemapHooks)) return addr; if (dxw.dwFlags2 & GDISTRETCHED) if (addr=RemapLibrary(proc, hModule, ScaledHooks)) return addr; if (dxw.dwFlags3 & GDIEMULATEDC) if (addr=RemapLibrary(proc, hModule, EmulateHooks)) return addr; @@ -232,84 +337,6 @@ extern HRESULT WINAPI sBlt(char *, LPDIRECTDRAWSURFACE, LPRECT, LPDIRECTDRAWSURF extern GetDC_Type pGetDC; extern ReleaseDC_Type pReleaseDC; -#if 0 -static COLORREF GetMatchingColor(COLORREF crColor) -{ - int iDistance, iMinDistance; - int iColorIndex, iMinColorIndex; - COLORREF PalColor; - - iMinDistance=0xFFFFFF; - iMinColorIndex=0; - - for(iColorIndex=0; iColorIndex<256; iColorIndex++){ - int iDist; - iDistance=0; - - PalColor=PaletteEntries[iColorIndex]; - switch(dxw.ActualPixelFormat.dwRGBBitCount){ - case 32: - PalColor = ((PalColor & 0x00FF0000) >> 16) | (PalColor & 0x0000FF00) | ((PalColor & 0x000000FF) << 16); - break; - case 16: - if(dxw.ActualPixelFormat.dwGBitMask==0x03E0){ - // RGB555 screen settings - PalColor = ((PalColor & 0x7C00) >> 7) | ((PalColor & 0x03E0) << 6) | ((PalColor & 0x001F) << 19); - } - else { - // RGB565 screen settings - PalColor = ((PalColor & 0xF800) >> 8) | ((PalColor & 0x07E0) << 5) | ((PalColor & 0x001F) << 19); - } - break; - } - - iDist = (crColor & 0x00FF0000) - (PalColor & 0x00FF0000); - iDist >>= 16; - if (iDist<0) iDist=-iDist; - iDist *= iDist; - iDistance += iDist; - - iDist = (crColor & 0x0000FF00) - (PalColor & 0x0000FF00); - iDist >>= 8; - if (iDist<0) iDist=-iDist; - iDist *= iDist; - iDistance += iDist; - - iDist = (crColor & 0x000000FF) - (PalColor & 0x000000FF); - // iDist >>= 0; - if (iDist<0) iDist=-iDist; - iDist *= iDist; - iDistance += iDist; - - if (iDistance < iMinDistance) { - iMinDistance = iDistance; - iMinColorIndex = iColorIndex; - } - - if (iMinDistance==0) break; // got the perfect match! - } - OutTraceDW("GetMatchingColor: color=%x matched with palette[%d]=%x dist=%d\n", - crColor, iMinColorIndex, PaletteEntries[iMinColorIndex], iDistance); - PalColor=PaletteEntries[iMinColorIndex]; - switch(dxw.ActualPixelFormat.dwRGBBitCount){ - case 32: - crColor = ((PalColor & 0x00FF0000) >> 16) | (PalColor & 0x0000FF00) | ((PalColor & 0x000000FF) << 16); - break; - case 16: - if(dxw.ActualPixelFormat.dwGBitMask==0x03E0){ - // RGB555 screen settings - crColor = ((PalColor & 0x7C00) >> 7) | ((PalColor & 0x03E0) << 6) | ((PalColor & 0x001F) << 19); - } - else { - // RGB565 screen settings - crColor = ((PalColor & 0xF800) >> 8) | ((PalColor & 0x07E0) << 5) | ((PalColor & 0x001F) << 19); - } - break; - } - return crColor; -} -#endif - //-------------------------------------------------------------------------------------------- // // API hookers @@ -343,16 +370,53 @@ int WINAPI extGetDeviceCaps(HDC hdc, int nindex) switch(nindex){ case VERTRES: if(dxw.Windowize){ - res= dxw.GetScreenHeight(); + if(dxw.IsDesktop(WindowFromDC(hdc))) + res= dxw.GetScreenHeight(); + else { + if(OBJ_DC == (*pGetObjectType)(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + case GDIMODE_EMULATED: + default: + break; + case GDIMODE_STRETCHED: + int dummy = 0; + dxw.UnmapClient(&dummy, (int *)&res); + break; + } + } + } OutTraceDW("GetDeviceCaps: fix(2) VERTRES cap=%d\n", res); } break; case HORZRES: if(dxw.Windowize){ - res= dxw.GetScreenWidth(); + if(dxw.IsDesktop(WindowFromDC(hdc))) + res= dxw.GetScreenWidth(); + else { + if(OBJ_DC == (*pGetObjectType)(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + case GDIMODE_EMULATED: + default: + break; + case GDIMODE_STRETCHED: + int dummy = 0; + dxw.UnmapClient((int *)&res, &dummy); + break; + } + } + } OutTraceDW("GetDeviceCaps: fix(2) HORZRES cap=%d\n", res); } break; + + + + if(dxw.Windowize){ + res= dxw.GetScreenWidth(); + } + break; // WARNING: in no-emu mode, the INIT8BPP and INIT16BPP flags expose capabilities that // are NOT implemented and may cause later troubles! case RASTERCAPS: @@ -408,15 +472,55 @@ BOOL WINAPI extTextOutA(HDC hdc, int nXStart, int nYStart, LPCTSTR lpString, int { BOOL ret; extern BOOL gFixed; - OutTraceDW("TextOut: hdc=%x xy=(%d,%d) str=(%d)\"%.*s\"\n", hdc, nXStart, nYStart, cchString, cchString, lpString); + OutTraceDW("TextOutA: hdc=%x xy=(%d,%d) str=(%d)\"%.*s\"\n", hdc, nXStart, nYStart, cchString, cchString, lpString); - if (!gFixed && dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ - dxw.MapClient(&nXStart, &nYStart); - OutTraceDW("TextOut: fixed dest=(%d,%d)\n", nXStart, nYStart); + if (!gFixed && dxw.IsToRemap(hdc)){ + + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pGDITextOutA)(sdc.GetHdc(), nXStart, nYStart, lpString, cchString); + // update whole screen to avoid make calculations about text position & size + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&nXStart, &nYStart); + OutTraceDW("TextOut: fixed dest=(%d,%d)\n", nXStart, nYStart); + break; + } } ret=(*pGDITextOutA)(hdc, nXStart, nYStart, lpString, cchString); - if(!ret) OutTraceE("TextOut: ERROR ret=%x\n", ret); + if(!ret) OutTraceE("TextOutA: ERROR ret=%x\n", ret); + return ret; +} + +BOOL WINAPI extTextOutW(HDC hdc, int nXStart, int nYStart, LPCWSTR lpString, int cchString) +{ + BOOL ret; + extern BOOL gFixed; + OutTraceDW("TextOutW: hdc=%x xy=(%d,%d) str=(%d)\"%.*ls\"\n", hdc, nXStart, nYStart, cchString, cchString, lpString); + + if (!gFixed && dxw.IsToRemap(hdc)){ + + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pGDITextOutW)(sdc.GetHdc(), nXStart, nYStart, lpString, cchString); + // update whole screen to avoid make calculations about text position & size + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&nXStart, &nYStart); + OutTraceDW("TextOutW: fixed dest=(%d,%d)\n", nXStart, nYStart); + break; + } + } + + ret=(*pGDITextOutW)(hdc, nXStart, nYStart, lpString, cchString); + if(!ret) OutTraceE("TextOutW: ERROR ret=%x\n", ret); return ret; } @@ -436,9 +540,19 @@ BOOL WINAPI extRectangle(HDC hdc, int nLeftRect, int nTopRect, int nRightRect, i OutTraceDW("Rectangle: hdc=%x xy=(%d,%d)-(%d,%d)\n", hdc, nLeftRect, nTopRect, nRightRect, nBottomRect); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ - dxw.MapClient(&nLeftRect, &nTopRect, &nRightRect, &nBottomRect); - OutTraceDW("Rectangle: fixed dest=(%d,%d)-(%d,%d)\n", nLeftRect, nTopRect, nRightRect, nBottomRect); + if (dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pGDIRectangle)(sdc.GetHdc(), nLeftRect, nTopRect, nRightRect, nBottomRect); + sdc.PutPrimaryDC(hdc, TRUE, nLeftRect, nTopRect, nRightRect-nLeftRect, nBottomRect-nTopRect); + return ret; + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&nLeftRect, &nTopRect, &nRightRect, &nBottomRect); + OutTraceDW("Rectangle: fixed dest=(%d,%d)-(%d,%d)\n", nLeftRect, nTopRect, nRightRect, nBottomRect); + break; + } } ret=(*pGDIRectangle)(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect); @@ -449,7 +563,6 @@ BOOL WINAPI extRectangle(HDC hdc, int nLeftRect, int nTopRect, int nRightRect, i int WINAPI extGDISaveDC(HDC hdc) { int ret; - ret=(*pGDISaveDC)(hdc); OutTraceDW("GDI.SaveDC: hdc=%x ret=%x\n", hdc, ret); return ret; @@ -458,7 +571,6 @@ int WINAPI extGDISaveDC(HDC hdc) BOOL WINAPI extGDIRestoreDC(HDC hdc, int nSavedDC) { BOOL ret; - ret=(*pGDIRestoreDC)(hdc, nSavedDC); OutTraceDW("GDI.RestoreDC: hdc=%x nSavedDC=%x ret=%x\n", hdc, nSavedDC, ret); return ret; @@ -593,7 +705,7 @@ HPALETTE WINAPI extSelectPalette(HDC hdc, HPALETTE hpal, BOOL bForceBackground) BOOL WINAPI extAnimatePalette(HPALETTE hpal, UINT iStartIndex, UINT cEntries, const PALETTEENTRY *ppe) { // Invoked by "Pharaoh's Ascent 1.4" - STOPPER("AnimatePalette"); + // STOPPER("AnimatePalette"); return TRUE; } @@ -675,31 +787,59 @@ UINT WINAPI extGetSystemPaletteUse(HDC hdc) return res; } -HDC WINAPI extGDICreateDC(LPSTR lpszDriver, LPSTR lpszDevice, LPSTR lpszOutput, CONST DEVMODE *lpdvmInit) +HDC WINAPI extGDICreateDCA(LPSTR lpszDriver, LPSTR lpszDevice, LPSTR lpszOutput, CONST DEVMODE *lpdvmInit) { HDC WinHDC, RetHDC; - OutTraceDW("GDI.CreateDC: Driver=%s Device=%s Output=%s InitData=%x\n", + OutTraceDW("GDI.CreateDCA: Driver=%s Device=%s Output=%s InitData=%x\n", lpszDriver?lpszDriver:"(NULL)", lpszDevice?lpszDevice:"(NULL)", lpszOutput?lpszOutput:"(NULL)", lpdvmInit); if (!lpszDriver || !strncmp(lpszDriver,"DISPLAY",7)) { - if(dxw.dwFlags3 & GDIEMULATEDC){ + if(dxw.GDIEmulationMode == GDIMODE_EMULATED){ RetHDC=dxw.AcquireEmulatedDC(dxw.GethWnd()); } else { - OutTraceDW("GDI.CreateDC: returning window surface DC\n"); - WinHDC=(*pGDIGetDC)(dxw.GethWnd()); - RetHDC=(*pGDICreateCompatibleDC)(WinHDC); - (*pGDIReleaseDC)(dxw.GethWnd(), WinHDC); + OutTraceDW("GDI.CreateDCA: returning window surface DC\n"); + WinHDC=(*pGDIGetDC)(dxw.GethWnd()); + RetHDC=(*pGDICreateCompatibleDC)(WinHDC); + (*pGDIReleaseDC)(dxw.GethWnd(), WinHDC); } } else{ - RetHDC=(*pGDICreateDC)(lpszDriver, lpszDevice, lpszOutput, lpdvmInit); + RetHDC=(*pGDICreateDCA)(lpszDriver, lpszDevice, lpszOutput, lpdvmInit); } if(RetHDC) - OutTraceDW("GDI.CreateDC: returning HDC=%x\n", RetHDC); + OutTraceDW("GDI.CreateDCA: returning HDC=%x\n", RetHDC); else - OutTraceE("GDI.CreateDC ERROR: err=%d at %d\n", GetLastError(), __LINE__); + OutTraceE("GDI.CreateDCA ERROR: err=%d at %d\n", GetLastError(), __LINE__); + return RetHDC; +} + +HDC WINAPI extGDICreateDCW(LPWSTR lpszDriver, LPWSTR lpszDevice, LPWSTR lpszOutput, CONST DEVMODE *lpdvmInit) +{ + HDC WinHDC, RetHDC; + OutTraceDW("GDI.CreateDCW: Driver=%ls Device=%ls Output=%ls InitData=%x\n", + lpszDriver?lpszDriver:L"(NULL)", lpszDevice?lpszDevice:L"(NULL)", lpszOutput?lpszOutput:L"(NULL)", lpdvmInit); + + if (!lpszDriver || !wcsncmp(lpszDriver,L"DISPLAY",7)) { + if(dxw.GDIEmulationMode == GDIMODE_EMULATED){ + RetHDC=dxw.AcquireEmulatedDC(dxw.GethWnd()); + } + else { + OutTraceDW("GDI.CreateDCW: returning window surface DC\n"); + WinHDC=(*pGDIGetDC)(dxw.GethWnd()); + RetHDC=(*pGDICreateCompatibleDC)(WinHDC); + (*pGDIReleaseDC)(dxw.GethWnd(), WinHDC); + } + + } + else{ + RetHDC=(*pGDICreateDCW)(lpszDriver, lpszDevice, lpszOutput, lpdvmInit); + } + if(RetHDC) + OutTraceDW("GDI.CreateDCW: returning HDC=%x\n", RetHDC); + else + OutTraceE("GDI.CreateDCW ERROR: err=%d at %d\n", GetLastError(), __LINE__); return RetHDC; } @@ -711,7 +851,7 @@ HDC WINAPI extCreateICA(LPCTSTR lpszDriver, LPCTSTR lpszDevice, LPCTSTR lpszOutp // EverQuest Tutorial.exe calls CreateICA passing "Tutorial" if(!lpszDriver || !_stricmp("DISPLAY", lpszDriver)){ - if(dxw.dwFlags3 & GDIEMULATEDC){ + if(dxw.GDIEmulationMode == GDIMODE_EMULATED){ RetHDC=dxw.AcquireEmulatedDC(dxw.GethWnd()); } else { @@ -758,46 +898,108 @@ HDC WINAPI extGDICreateCompatibleDC(HDC hdc) return RetHdc; } +/*----------------------------------------*/ +HBITMAP VirtualPic; + +static HDC FillVirtualDC(HDC hdc) +{ + HDC VirtualHDC; + HBITMAP VirtualPic; + + if(!(VirtualHDC=CreateCompatibleDC(hdc))) + OutTraceE("CreateCompatibleDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + + if(!(VirtualPic=CreateCompatibleBitmap(hdc, dxw.GetScreenWidth(), dxw.GetScreenHeight()))) + OutTraceE("dxwSDC::GetPrimaryDC: CreateCompatibleBitmap ERROR err=%d at=%d\n", GetLastError(), __LINE__); + + if(!SelectObject(VirtualHDC, VirtualPic)) + OutTraceE("dxwSDC::GetPrimaryDC: SelectObject ERROR err=%d at=%d\n", GetLastError(), __LINE__); + + if(!(*pGDIBitBlt)(VirtualHDC, 0, 0, dxw.GetScreenWidth(), dxw.GetScreenHeight(), hdc, 0, 0, SRCCOPY)) + OutTraceE("dxwSDC::GetPrimaryDC: StretchBlt ERROR err=%d at=%d\n", GetLastError(), __LINE__); + + return VirtualHDC; +} + +static void FlushVirtualDC(HDC VirtualHDC) +{ + DeleteObject(VirtualHDC); + DeleteObject(VirtualPic); +} + +/*-------------------------------------------*/ + BOOL WINAPI extGDIBitBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop) { BOOL res; BOOL IsToScreen; + BOOL IsFromScreen; + BOOL IsDCLeakageSrc = FALSE; + BOOL IsDCLeakageDest = FALSE; + int Flux; - OutTraceDW("GDI.BitBlt: HDC=%x nXDest=%d nYDest=%d nWidth=%d nHeight=%d hdcSrc=%x nXSrc=%d nYSrc=%d dwRop=%x(%s)\n", - hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, dwRop, ExplainROP(dwRop)); + OutTraceDW("GDI.BitBlt: HDC=%x(type=%s) nXDest=%d nYDest=%d nWidth=%d nHeight=%d hdcSrc=%x(type=%s) nXSrc=%d nYSrc=%d dwRop=%x(%s)\n", + hdcDest, GetObjectTypeStr(hdcDest), nXDest, nYDest, nWidth, nHeight, + hdcSrc, GetObjectTypeStr(hdcSrc), nXSrc, nYSrc, dwRop, ExplainROP(dwRop)); OutTraceB("GDI.BitBlt: DEBUG FullScreen=%x target hdctype=%x(%s) hwnd=%x\n", - dxw.IsFullScreen(), GetObjectType(hdcDest), ExplainDCType(GetObjectType(hdcDest)), WindowFromDC(hdcDest)); + dxw.IsFullScreen(), (*pGetObjectType)(hdcDest), ExplainDCType((*pGetObjectType)(hdcDest)), WindowFromDC(hdcDest)); // beware: HDC could refer to screen DC that are written directly on screen, or memory DC that will be scaled to // the screen surface later on, on ReleaseDC or ddraw Blit / Flip operation. Scaling of rect coordinates is // needed only in the first case, and must be avoided on the second, otherwise the image would be scaled twice! - if(dxw.dwFlags3 & GDIEMULATEDC){ - if (hdcDest==dxw.RealHDC) hdcDest=dxw.VirtualHDC; - OutTraceB("GDI.BitBlt: DEBUG emulated hdc dest=%x->%x\n", dxw.RealHDC, hdcDest); - } - if(hdcDest == NULL){ // happens in Reah, hdc is NULL despite the fact that BeginPaint returns a valid DC. Too bad, we recover here ... hdcDest = (*pGDIGetDC)(dxw.GethWnd()); - OutTraceB("GDI.BitBlt: DEBUG hdc dest=NULL->%x\n", hdcDest); + OutTraceB("GDI.StretchBlt: DEBUG hdc dest=NULL->%x\n", hdcDest); + IsDCLeakageDest = TRUE; + } + if(hdcSrc == NULL){ + hdcSrc = (*pGDIGetDC)(dxw.GethWnd()); + OutTraceB("GDI.StretchBlt: DEBUG hdc src=NULL->%x\n", hdcSrc); + IsDCLeakageSrc = TRUE; } - IsToScreen=(OBJ_DC == GetObjectType(hdcDest)); + IsToScreen=(OBJ_DC == (*pGetObjectType)(hdcDest)); + IsFromScreen=(OBJ_DC == (*pGetObjectType)(hdcSrc)); + Flux = (IsToScreen ? 1 : 0) + (IsFromScreen ? 2 : 0); if (IsToScreen && (dxw.dwFlags3 & NOGDIBLT)) return TRUE; - if(dxw.IsFullScreen()) { + + if(dxw.IsFullScreen()){ + //int nWSrc, nHSrc, + int nWDest, nHDest; switch(dxw.GDIEmulationMode){ - case GDIMODE_STRETCHED: { - int nWDest, nHDest; - nWDest= nWidth; - nHDest= nHeight; - dxw.MapClient(&nXDest, &nYDest, &nWDest, &nHDest); - res=(*pGDIStretchBlt)(hdcDest, nXDest, nYDest, nWDest, nHDest, hdcSrc, nXSrc, nYSrc, nWidth, nHeight, dwRop); - OutTraceB("GDI.BitBlt: DEBUG DC dest=(%d,%d) size=(%d,%d)\n", nXDest, nYDest, nWDest, nHDest); + case GDIMODE_SHAREDDC: + switch(Flux){ + case 0: // memory to memory + res=(*pGDIBitBlt)(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, dwRop); + break; + case 1: // memory to screen + case 3: // screen to screen + sdc.GetPrimaryDC(hdcDest); + res=(*pGDIBitBlt)(sdc.GetHdc(), nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, dwRop); + sdc.PutPrimaryDC(hdcDest, TRUE, nXDest, nYDest, nWidth, nHeight); + break; + case 2: // screen to memory + sdc.GetPrimaryDC(hdcSrc); + res=(*pGDIBitBlt)(hdcDest, nXDest, nYDest, nWidth, nHeight, sdc.GetHdc(), nXSrc, nYSrc, dwRop); + sdc.PutPrimaryDC(hdcSrc, FALSE); + break; } break; + case GDIMODE_STRETCHED: + nWDest= nWidth; + nHDest= nHeight; + if (IsToScreen && !IsFromScreen) dxw.MapClient(&nXDest, &nYDest, &nWDest, &nHDest); + res=(*pGDIStretchBlt)(hdcDest, nXDest, nYDest, nWDest, nHDest, hdcSrc, nXSrc, nYSrc, nWidth, nHeight, dwRop); + OutTraceB("GDI.BitBlt: DEBUG DC dest=(%d,%d) size=(%d,%d)\n", nXDest, nYDest, nWDest, nHDest); + break; case GDIMODE_EMULATED: + if (hdcDest==dxw.RealHDC) hdcDest=dxw.VirtualHDC; + res=(*pGDIBitBlt)(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, dwRop); + OutTraceB("GDI.BitBlt: DEBUG emulated hdc dest=%x->%x\n", dxw.RealHDC, hdcDest); + break; default: res=(*pGDIBitBlt)(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, dwRop); break; @@ -807,23 +1009,110 @@ BOOL WINAPI extGDIBitBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nH res=(*pGDIBitBlt)(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, dwRop); } + if(IsDCLeakageSrc) (*pGDIReleaseDC)(dxw.GethWnd(), hdcSrc); + if(IsDCLeakageDest) (*pGDIReleaseDC)(dxw.GethWnd(), hdcDest); if(res && IsToScreen) dxw.ShowOverlay(hdcDest); if(!res) OutTraceE("GDI.BitBlt: ERROR err=%d at %d\n", GetLastError(), __LINE__); return res; } +BOOL WINAPI extGDIStretchBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, + HDC hdcSrc, int nXSrc, int nYSrc, int nWSrc, int nHSrc, DWORD dwRop) +{ + BOOL res; + BOOL IsToScreen; + BOOL IsFromScreen; + BOOL IsDCLeakageSrc = FALSE; + BOOL IsDCLeakageDest = FALSE; + int Flux; + + OutTraceDW("GDI.StretchBlt: HDC=%x nXDest=%d nYDest=%d nWidth=%d nHeight=%d hdcSrc=%x nXSrc=%d nYSrc=%d nWSrc=%d nHSrc=%d dwRop=%x(%s)\n", + hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, nWSrc, nHSrc, dwRop, ExplainROP(dwRop)); + + OutTraceB("GDI.StretchBlt: DEBUG FullScreen=%x target hdctype=%x(%s) hwnd=%x\n", + dxw.IsFullScreen(), (*pGetObjectType)(hdcDest), ExplainDCType((*pGetObjectType)(hdcDest)), WindowFromDC(hdcDest)); + + if(dxw.GDIEmulationMode == GDIMODE_EMULATED){ + if (hdcDest==dxw.RealHDC) hdcDest=dxw.VirtualHDC; + OutTraceB("GDI.StretchBlt: DEBUG emulated hdc dest=%x->%x\n", dxw.RealHDC, hdcDest); + } + + if(hdcDest == NULL){ + // happens in Reah, hdc is NULL despite the fact that BeginPaint returns a valid DC. Too bad, we recover here ... + hdcDest = (*pGDIGetDC)(dxw.GethWnd()); + OutTraceB("GDI.StretchBlt: DEBUG hdc dest=NULL->%x\n", hdcDest); + IsDCLeakageDest = TRUE; + } + if(hdcSrc == NULL){ + hdcSrc = (*pGDIGetDC)(dxw.GethWnd()); + OutTraceB("GDI.StretchBlt: DEBUG hdc src=NULL->%x\n", hdcSrc); + IsDCLeakageSrc = TRUE; + } + + IsToScreen=(OBJ_DC == (*pGetObjectType)(hdcDest)); + IsFromScreen=(OBJ_DC == (*pGetObjectType)(hdcSrc)); + Flux = (IsToScreen ? 1 : 0) + (IsFromScreen ? 2 : 0); + if (IsToScreen && (dxw.dwFlags3 & NOGDIBLT)) return TRUE; + + if(dxw.IsToRemap(hdcDest) && (hdcDest != hdcSrc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + switch(Flux){ + case 0: // memory to memory + res=(*pGDIStretchBlt)(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, nWSrc, nHSrc, dwRop); + break; + case 1: // memory to screen + case 3: // screen to screen + sdc.GetPrimaryDC(hdcDest); + res=(*pGDIStretchBlt)(sdc.GetHdc(), nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, nWSrc, nHSrc, dwRop); + sdc.PutPrimaryDC(hdcDest, TRUE, nXDest, nYDest, nWidth, nHeight); + break; + case 2: // screen to memory using virtual screen + sdc.GetPrimaryDC(hdcSrc); + res=(*pGDIStretchBlt)(hdcDest, nXDest, nYDest, nWidth, nHeight, sdc.GetHdc(), nXSrc, nYSrc, nWSrc, nHSrc, dwRop); + sdc.PutPrimaryDC(hdcSrc, FALSE, nXSrc, nYSrc, nWSrc, nHSrc); + break; + } + break; + case GDIMODE_STRETCHED: { + int nWDest, nHDest; + nWDest= nWidth; + nHDest= nHeight; + dxw.MapClient(&nXDest, &nYDest, &nWDest, &nHDest); + res=(*pGDIStretchBlt)(hdcDest, nXDest, nYDest, nWDest, nHDest, hdcSrc, nXSrc, nYSrc, nWSrc, nHSrc, dwRop); + OutTraceB("GDI.StretchBlt: DEBUG DC dest=(%d,%d) size=(%d,%d)\n", nXDest, nYDest, nWDest, nHDest); + } + break; + case GDIMODE_EMULATED: + default: + res=(*pGDIStretchBlt)(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, nWSrc, nHSrc, dwRop); + break; + } + } + else { + res=(*pGDIStretchBlt)(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, nWSrc, nHSrc, dwRop); + } + + if(IsDCLeakageSrc) (*pGDIReleaseDC)(dxw.GethWnd(), hdcSrc); + if(IsDCLeakageDest) (*pGDIReleaseDC)(dxw.GethWnd(), hdcDest); + if(res && IsToScreen) dxw.ShowOverlay(hdcDest); + if(!res) OutTraceE("GDI.StretchBlt: ERROR err=%d at %d\n", GetLastError(), __LINE__); + return res; +} + BOOL WINAPI extGDIPatBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, DWORD dwRop) { BOOL res; BOOL IsToScreen; + BOOL IsDCLeakageDest = FALSE; OutTraceDW("GDI.PatBlt: HDC=%x nXDest=%d nYDest=%d nWidth=%d nHeight=%d dwRop=%x(%s)\n", hdcDest, nXDest, nYDest, nWidth, nHeight, dwRop, ExplainROP(dwRop)); OutTraceB("GDI.PatBlt: DEBUG FullScreen=%x target hdctype=%x(%s) hwnd=%x\n", - dxw.IsFullScreen(), GetObjectType(hdcDest), ExplainDCType(GetObjectType(hdcDest)), WindowFromDC(hdcDest)); + dxw.IsFullScreen(), (*pGetObjectType)(hdcDest), ExplainDCType((*pGetObjectType)(hdcDest)), WindowFromDC(hdcDest)); - if(dxw.dwFlags3 & GDIEMULATEDC){ + if(dxw.GDIEmulationMode == GDIMODE_EMULATED){ if (hdcDest==dxw.RealHDC) hdcDest=dxw.VirtualHDC; OutTraceB("GDI.PatBlt: DEBUG emulated hdc dest=%x->%x\n", dxw.RealHDC, hdcDest); } @@ -832,12 +1121,22 @@ BOOL WINAPI extGDIPatBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nH // happens in Reah, hdc is NULL despite the fact that BeginPaint returns a valid DC. Too bad, we recover here ... hdcDest = (*pGDIGetDC)(dxw.GethWnd()); OutTraceB("GDI.PatBlt: DEBUG hdc dest=NULL->%x\n", hdcDest); + IsDCLeakageDest = TRUE; } - IsToScreen=(OBJ_DC == GetObjectType(hdcDest)); + IsToScreen=(OBJ_DC == (*pGetObjectType)(hdcDest)); + if (IsToScreen && (dxw.dwFlags3 & NOGDIBLT)) return TRUE; - if(dxw.IsFullScreen()) { + + if(dxw.IsToRemap(hdcDest)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdcDest); + res=(*pGDIPatBlt)(sdc.GetHdc(), nXDest, nYDest, nWidth, nHeight, dwRop); + sdc.PutPrimaryDC(hdcDest, TRUE, nXDest, nYDest, nWidth, nHeight); + return res; + break; case GDIMODE_STRETCHED: { int nWDest, nHDest; nWDest= nWidth; @@ -857,62 +1156,12 @@ BOOL WINAPI extGDIPatBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nH res=(*pGDIPatBlt)(hdcDest, nXDest, nYDest, nWidth, nHeight, dwRop); } + if(IsDCLeakageDest) (*pGDIReleaseDC)(dxw.GethWnd(), hdcDest); if(res && IsToScreen) dxw.ShowOverlay(hdcDest); if(!res) OutTraceE("GDI.PatBlt: ERROR err=%d at %d\n", GetLastError(), __LINE__); return res; } -BOOL WINAPI extGDIStretchBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, - HDC hdcSrc, int nXSrc, int nYSrc, int nWSrc, int nHSrc, DWORD dwRop) -{ - BOOL res; - BOOL IsToScreen; - - OutTraceDW("GDI.StretchBlt: HDC=%x nXDest=%d nYDest=%d nWidth=%d nHeight=%d hdcSrc=%x nXSrc=%d nYSrc=%d nWSrc=%d nHSrc=%d dwRop=%x(%s)\n", - hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, nWSrc, nHSrc, dwRop, ExplainROP(dwRop)); - - OutTraceB("GDI.StretchBlt: DEBUG FullScreen=%x target hdctype=%x(%s) hwnd=%x\n", - dxw.IsFullScreen(), GetObjectType(hdcDest), ExplainDCType(GetObjectType(hdcDest)), WindowFromDC(hdcDest)); - - if(dxw.dwFlags3 & GDIEMULATEDC){ - if (hdcDest==dxw.RealHDC) hdcDest=dxw.VirtualHDC; - OutTraceB("GDI.StretchBlt: DEBUG emulated hdc dest=%x->%x\n", dxw.RealHDC, hdcDest); - } - - if(hdcDest == NULL){ - // happens in Reah, hdc is NULL despite the fact that BeginPaint returns a valid DC. Too bad, we recover here ... - hdcDest = (*pGDIGetDC)(dxw.GethWnd()); - OutTraceB("GDI.StretchBlt: DEBUG hdc dest=NULL->%x\n", hdcDest); - } - - IsToScreen=(OBJ_DC == GetObjectType(hdcDest)); - if (IsToScreen && (dxw.dwFlags3 & NOGDIBLT)) return TRUE; - if(dxw.IsFullScreen()) { - switch(dxw.GDIEmulationMode){ - case GDIMODE_STRETCHED: { - int nWDest, nHDest; - nWDest= nWidth; - nHDest= nHeight; - dxw.MapClient(&nXDest, &nYDest, &nWDest, &nHDest); - res=(*pGDIStretchBlt)(hdcDest, nXDest, nYDest, nWDest, nHDest, hdcSrc, nXSrc, nYSrc, nWidth, nHeight, dwRop); - OutTraceB("GDI.StretchBlt: DEBUG DC dest=(%d,%d) size=(%d,%d)\n", nXDest, nYDest, nWDest, nHDest); - } - break; - case GDIMODE_EMULATED: - default: - res=(*pGDIStretchBlt)(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, nWidth, nHeight, dwRop); - break; - } - } - else { - res=(*pGDIStretchBlt)(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, nWidth, nHeight, dwRop); - } - - if(res && IsToScreen) dxw.ShowOverlay(hdcDest); - if(!res) OutTraceE("GDI.StretchBlt: ERROR err=%d at %d\n", GetLastError(), __LINE__); - return res; -} - BOOL WINAPI extGDIDeleteDC(HDC hdc) { BOOL res; @@ -989,26 +1238,36 @@ BOOL WINAPI extGetDeviceGammaRamp(HDC hDC, LPVOID lpRamp) return ret; } -static char *sClipType(int t) -{ - static char *sRetCodes[4]={"ERROR", "NULLREGION", "SIMPLEREGION", "COMPLEXREGION"}; - if(t<0 || t>3) return "Unknown"; - return sRetCodes[t]; -} - int WINAPI extGetClipBox(HDC hdc, LPRECT lprc) { // v2.02.31: needed in "Imperialism II" to avoid blit clipping int ret; OutTraceDW("GetClipBox: hdc=%x\n", hdc); - ret=(*pGDIGetClipBox)(hdc, lprc); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc)) && (ret!=ERROR)){ - OutTraceDW("GetClipBox: scaling main win coordinates (%d,%d)-(%d,%d)\n", - lprc->left, lprc->top, lprc->right, lprc->bottom); - dxw.UnmapClient(lprc); + + if (dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pGDIGetClipBox)(sdc.GetHdc(), lprc); + sdc.PutPrimaryDC(hdc, FALSE); + return ret; + break; + case GDIMODE_STRETCHED: + ret=(*pGDIGetClipBox)(hdc, lprc); + OutTraceDW("GetClipBox: scaling main win coordinates (%d,%d)-(%d,%d)\n", + lprc->left, lprc->top, lprc->right, lprc->bottom); + dxw.UnmapClient(lprc); + break; + default: + ret=(*pGDIGetClipBox)(hdc, lprc); + break; + } } + else + ret=(*pGDIGetClipBox)(hdc, lprc); + OutTraceDW("GetClipBox: ret=%x(%s) rect=(%d,%d)-(%d,%d)\n", - ret, sClipType(ret), lprc->left, lprc->top, lprc->right, lprc->bottom); + ret, ExplainRegionType(ret), lprc->left, lprc->top, lprc->right, lprc->bottom); return ret; } @@ -1017,13 +1276,23 @@ int WINAPI extIntersectClipRect(HDC hdc, int nLeftRect, int nTopRect, int nRight int ret; OutTraceDW("IntersectClipRect: hdc=%x rect=(%d,%d)-(%d,%d)\n", hdc, nLeftRect, nTopRect, nRightRect, nBottomRect); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ - dxw.MapClient(&nLeftRect, &nTopRect, &nRightRect, &nBottomRect); - OutTraceDW("IntersectClipRect: fixed rect=(%d,%d)-(%d,%d)\n", nLeftRect, nTopRect, nRightRect, nBottomRect); + if (dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pIntersectClipRect)(sdc.GetHdc(), nLeftRect, nTopRect, nRightRect, nBottomRect); + sdc.PutPrimaryDC(hdc, FALSE); + return ret; + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&nLeftRect, &nTopRect, &nRightRect, &nBottomRect); + OutTraceDW("IntersectClipRect: fixed rect=(%d,%d)-(%d,%d)\n", nLeftRect, nTopRect, nRightRect, nBottomRect); + break; + } } ret=(*pIntersectClipRect)(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect); - OutTraceE("CreateRectRgnIndirect: ret=%x(%s)\n", ret, sClipType(ret)); + OutTraceE("IntersectClipRect: ret=%x(%s)\n", ret, ExplainRegionType(ret)); return ret; } @@ -1032,10 +1301,14 @@ int WINAPI extGetRgnBox(HRGN hrgn, LPRECT lprc) int ret; OutTraceDW("GetRgnBox: hrgn=%x\n", hrgn); ret=(*pGetRgnBox)(hrgn, lprc); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hrgn)) && (ret!=ERROR)){ - OutTraceDW("GetRgnBox: scaling main win coordinates (%d,%d)-(%d,%d)\n", - lprc->left, lprc->top, lprc->right, lprc->bottom); - dxw.UnmapClient(lprc); + if (dxw.IsFullScreen() && (ret!=ERROR)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_STRETCHED: + OutTraceDW("GetRgnBox: scaling main win coordinates (%d,%d)-(%d,%d)\n", + lprc->left, lprc->top, lprc->right, lprc->bottom); + dxw.UnmapClient(lprc); + break; + } } OutTraceDW("GetRgnBox: ret=%x(%s) rect=(%d,%d)-(%d,%d)\n", ret, ExplainRegionType(ret), lprc->left, lprc->top, lprc->right, lprc->bottom); @@ -1052,14 +1325,25 @@ BOOL WINAPI extPolyline(HDC hdc, const POINT *lppt, int cPoints) for(i=0; ibmiHeader); OutTraceDW("SetDIBits: BitmapInfo dim=(%dx%d) Planes=%d BPP=%d Compression=%x SizeImage=%x\n", bmi->biWidth, bmi->biHeight, bmi->biPlanes, bmi->biBitCount, bmi->biCompression, bmi->biSizeImage); - ret = (*pSetDIBits)(hdc, hbmp, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse); - OutTraceDW("SetDIBits: ret=%d\n", ret); - return ret; - //return cScanLines; - //return (*pSetDIBits)(hdc, hbmp, uStartScan, cScanLines, lpvBits, lpbmi, DIB_PAL_COLORS); - //return (*pSetDIBits)(hdc, hbmp, uStartScan, cScanLines, lpvBits, lpbmi, DIB_RGB_COLORS); + if(dxw.IsToRemap(hdc) && !bGDIRecursionFlag){ + //HDC hTempDc; + //HBITMAP hbmPic; + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: // this will flicker !!!! + sdc.GetPrimaryDC(hdc); + ret=(*pSetDIBits)(sdc.GetHdc(), hbmp, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse); + sdc.PutPrimaryDC(hdc, TRUE, 0, 0, bmi->biWidth, bmi->biHeight); + return ret; + break; + case GDIMODE_STRETCHED: +#if 0 + // blitting to primary surface !!! + int OrigXDest, OrigYDest; + OrigWidth=dwWidth; + OrigHeight=dwHeight; + OrigXDest=XDest; + OrigYDest=YDest; + dxw.MapClient(&XDest, &YDest, (int *)&dwWidth, (int *)&dwHeight); + OutTraceDW("SetDIBitsToDevice: fixed dest=(%d,%d)-(%dx%d)\n", XDest, YDest, dwWidth, dwHeight); + if(!(hTempDc=CreateCompatibleDC(hdc))) + OutTraceE("CreateCompatibleDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + // tricky part: CreateCompatibleBitmap is needed to set the dc size, but it has to be performed + // against hdc to set for color depth, then selected (through SelectObject) against the temporary + // dc to assign the needed size and color space to the temporary dc. + if(!(hbmPic=CreateCompatibleBitmap(hdc, OrigWidth, OrigHeight))) + OutTraceE("CreateCompatibleBitmap: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + if(!SelectObject(hTempDc, hbmPic)) + OutTraceE("SelectObject: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + if(!(*pSetDIBits)(hTempDc, hbmp, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse)) + OutTraceE("SetDIBitsToDevice: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + // v2.02.94: set HALFTONE stretching. Fixes "Celtic Kings Rage of War" + SetStretchBltMode(hdc,HALFTONE); + if(!(ret=(*pGDIStretchBlt)(hdc, XDest, YDest, dwWidth, dwHeight, hTempDc, 0, 0, OrigWidth, OrigHeight, SRCCOPY))) + OutTraceE("StretchBlt: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + if(!(DeleteObject(hbmPic))) // v2.02.32 - avoid resource leakage + OutTraceE("DeleteObject: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + if(!(DeleteDC(hTempDc))) + OutTraceE("DeleteDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + return TRUE; +#endif + break; + case GDIMODE_EMULATED: +#if 0 + if (dxw.IsVirtual(hdc)){ + int X, Y; + X=XDest+dxw.VirtualOffsetX; + Y=YDest+dxw.VirtualOffsetY; + OutTraceDW("SetDIBitsToDevice: virtual pos=(%d,%d)+(%d+%d)=(%d,%d)\n", + XDest, YDest, dxw.VirtualOffsetX, dxw.VirtualOffsetY, X, Y); + ret=(*pSetDIBits)(sdc.GetHdc(), hbmp, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse); + if(!ret || (ret==GDI_ERROR)) OutTraceE("SetDIBitsToDevice: ERROR ret=%x err=%d\n", ret, GetLastError()); + return ret; + } +#endif + break; + default: + break; + } + } + + return (*pSetDIBits)(hdc, hbmp, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse); + if(!ret || (ret==GDI_ERROR)) OutTraceE("SetDIBits: ERROR err=%d\n", GetLastError()); + return ret; } +int WINAPI extGetDIBits(HDC hdc, HBITMAP hbmp, UINT uStartScan, UINT cScanLines, LPVOID lpvBits, LPBITMAPINFO lpbmi, UINT uUsage) +{ + int ret; + BITMAPINFOHEADER *bmi; + OutTraceDW("GetDIBits: hdc=%x hbmp=%x lines=(%d,%d) ColorUse=%x\n", hdc, hbmp, uStartScan, cScanLines, uUsage); + bmi=(BITMAPINFOHEADER *)&(lpbmi->bmiHeader); + OutTraceDW("GetDIBits: BitmapInfo dim=(%dx%d) Planes=%d BPP=%d Compression=%x SizeImage=%x\n", + bmi->biWidth, bmi->biHeight, bmi->biPlanes, bmi->biBitCount, bmi->biCompression, bmi->biSizeImage); + + if(dxw.IsToRemap(hdc) && !bGDIRecursionFlag){ + //HDC hTempDc; + //HBITMAP hbmPic; + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: // this will flicker !!!! + sdc.GetPrimaryDC(hdc); + ret=(*pGetDIBits)(sdc.GetHdc(), hbmp, uStartScan, cScanLines, lpvBits, lpbmi, uUsage); + sdc.PutPrimaryDC(hdc, FALSE); + return ret; + break; + case GDIMODE_EMULATED: + default: + break; + } + } + + return (*pGetDIBits)(hdc, hbmp, uStartScan, cScanLines, lpvBits, lpbmi, uUsage); + if(!ret || (ret==GDI_ERROR)) OutTraceE("GetDIBits: ERROR err=%d\n", GetLastError()); + return ret; +} + +#if 0 int WINAPI extSetDIBitsToDevice(HDC hdc, int XDest, int YDest, DWORD dwWidth, DWORD dwHeight, int XSrc, int YSrc, UINT uStartScan, UINT cScanLines, const VOID *lpvBits, const BITMAPINFO *lpbmi, UINT fuColorUse) { @@ -1232,87 +1804,204 @@ int WINAPI extSetDIBitsToDevice(HDC hdc, int XDest, int YDest, DWORD dwWidth, DW OutTraceDW("SetDIBitsToDevice: BitmapInfo dim=(%dx%d) Planes=%d BPP=%d Compression=%x SizeImage=%x\n", bmi->biWidth, bmi->biHeight, bmi->biPlanes, bmi->biBitCount, bmi->biCompression, bmi->biSizeImage); - if (dxw.IsFullScreen() && dxw.IsVirtual(hdc)){ - int X, Y; - X=XDest+dxw.VirtualOffsetX; - Y=YDest+dxw.VirtualOffsetY; - OutTraceDW("SetDIBitsToDevice: virtual pos=(%d,%d)+(%d+%d)=(%d,%d)\n", - XDest, YDest, dxw.VirtualOffsetX, dxw.VirtualOffsetY, X, Y); - ret=(*pSetDIBitsToDevice)(hdc, X, Y, dwWidth, dwHeight, XSrc, YSrc, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse); - if(!ret || (ret==GDI_ERROR)) OutTraceE("SetDIBitsToDevice: ERROR ret=%x err=%d\n", ret, GetLastError()); - return ret; - } - //else - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ - // blitting to primary surface !!! + bGDIRecursionFlag = TRUE; // beware: it seems that SetDIBitsToDevice calls SetDIBits internally + if(dxw.IsFullScreen()){ + HDC hTempDc; + HBITMAP hbmPic; DWORD OrigWidth, OrigHeight; int OrigXDest, OrigYDest; OrigWidth=dwWidth; OrigHeight=dwHeight; OrigXDest=XDest; OrigYDest=YDest; - dxw.MapClient(&XDest, &YDest, (int *)&dwWidth, (int *)&dwHeight); - OutTraceDW("SetDIBitsToDevice: fixed dest=(%d,%d)-(%dx%d)\n", XDest, YDest, dwWidth, dwHeight); - HDC hTempDc; - HBITMAP hbmPic; - - if(dxw.HandleFPS()) return DD_OK; - if(dxw.dwFlags5 & NOBLT) return DD_OK; - - if(!(hTempDc=CreateCompatibleDC(hdc))) - OutTraceE("CreateCompatibleDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__); - // tricky part: CreateCompatibleBitmap is needed to set the dc size, but it has to be performed - // against hdc to set for color depth, then selected (through SelectObject) against the temporary - // dc to assign the needed size and color space to the temporary dc. - if(!(hbmPic=CreateCompatibleBitmap(hdc, OrigWidth, OrigHeight))) - OutTraceE("CreateCompatibleBitmap: ERROR err=%d at=%d\n", GetLastError(), __LINE__); - if(!SelectObject(hTempDc, hbmPic)) - OutTraceE("SelectObject: ERROR err=%d at=%d\n", GetLastError(), __LINE__); - if(!(*pSetDIBitsToDevice)(hTempDc, 0, 0, OrigWidth, OrigHeight, XSrc, YSrc, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse)) - OutTraceE("SetDIBitsToDevice: ERROR err=%d at=%d\n", GetLastError(), __LINE__); - // v2.02.94: set HALFTONE stretching. Fixes "Celtic Kings Rage of War" - SetStretchBltMode(hdc,HALFTONE); - if(!(ret=(*pGDIStretchBlt)(hdc, XDest, YDest, dwWidth, dwHeight, hTempDc, 0, 0, OrigWidth, OrigHeight, SRCCOPY))) - OutTraceE("StretchBlt: ERROR err=%d at=%d\n", GetLastError(), __LINE__); - - dxw.ShowOverlay(hdc); - - if(!(DeleteObject(hbmPic))) // v2.02.32 - avoid resource leakage - OutTraceE("DeleteObject: ERROR err=%d at=%d\n", GetLastError(), __LINE__); - if(!(DeleteDC(hTempDc))) - OutTraceE("DeleteDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__); - } - else{ - ret=(*pSetDIBitsToDevice)(hdc, XDest, YDest, dwWidth, dwHeight, XSrc, YSrc, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse); + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + if(dxw.IsToRemap(hdc)){ + sdc.GetPrimaryDC(hdc); + ret=(*pSetDIBitsToDevice)(sdc.GetHdc(), XDest, YDest, dwWidth, dwHeight, XSrc, YSrc, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse); + sdc.PutPrimaryDC(hdc, TRUE, XDest, YDest, dwWidth, dwHeight); + } + else{ + ret=(*pSetDIBitsToDevice)(hdc, XDest, YDest, dwWidth, dwHeight, XSrc, YSrc, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse); + } + bGDIRecursionFlag = FALSE; + return ret; + break; + case GDIMODE_STRETCHED: + if(dxw.IsToRemap(hdc)){ + // blitting to primary surface !!! + dxw.MapClient(&XDest, &YDest, (int *)&dwWidth, (int *)&dwHeight); + OutTraceDW("SetDIBitsToDevice: fixed dest=(%d,%d)-(%dx%d)\n", XDest, YDest, dwWidth, dwHeight); + if(!(hTempDc=CreateCompatibleDC(hdc))) + OutTraceE("CreateCompatibleDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + // tricky part: CreateCompatibleBitmap is needed to set the dc size, but it has to be performed + // against hdc to set for color depth, then selected (through SelectObject) against the temporary + // dc to assign the needed size and color space to the temporary dc. + if(!(hbmPic=CreateCompatibleBitmap(hdc, OrigWidth, OrigHeight))) + OutTraceE("CreateCompatibleBitmap: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + if(!SelectObject(hTempDc, hbmPic)) + OutTraceE("SelectObject: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + if(!(ret=(*pSetDIBitsToDevice)(hTempDc, 0, 0, OrigWidth, OrigHeight, XSrc, YSrc, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse))) + OutTraceE("SetDIBitsToDevice: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + bGDIRecursionFlag = FALSE; + // v2.02.94: set HALFTONE stretching. Fixes "Celtic Kings Rage of War" + SetStretchBltMode(hdc,HALFTONE); + if(!(ret=(*pGDIStretchBlt)(hdc, XDest, YDest, dwWidth, dwHeight, hTempDc, 0, 0, OrigWidth, OrigHeight, SRCCOPY))) + OutTraceE("StretchBlt: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + if(!(DeleteObject(hbmPic))) // v2.02.32 - avoid resource leakage + OutTraceE("DeleteObject: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + if(!(DeleteDC(hTempDc))) + OutTraceE("DeleteDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + return ret; + } + break; + case GDIMODE_EMULATED: + if (dxw.IsVirtual(hdc)){ + int X, Y; + X=XDest+dxw.VirtualOffsetX; + Y=YDest+dxw.VirtualOffsetY; + OutTraceDW("SetDIBitsToDevice: virtual pos=(%d,%d)+(%d+%d)=(%d,%d)\n", + XDest, YDest, dxw.VirtualOffsetX, dxw.VirtualOffsetY, X, Y); + ret=(*pSetDIBitsToDevice)(hdc, X, Y, dwWidth, dwHeight, XSrc, YSrc, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse); + bGDIRecursionFlag = FALSE; + if(!ret || (ret==GDI_ERROR)) OutTraceE("SetDIBitsToDevice: ERROR ret=%x err=%d\n", ret, GetLastError()); + return ret; + } + break; + default: + break; + } } + + ret=(*pSetDIBitsToDevice)(hdc, XDest, YDest, dwWidth, dwHeight, XSrc, YSrc, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse); + bGDIRecursionFlag = FALSE; if(!ret || (ret==GDI_ERROR)) OutTraceE("SetDIBitsToDevice: ERROR ret=%x err=%d\n", ret, GetLastError()); return ret; } +#else +int WINAPI extSetDIBitsToDevice(HDC hdc, int XDest, int YDest, DWORD dwWidth, DWORD dwHeight, int XSrc, int YSrc, UINT uStartScan, UINT cScanLines, + const VOID *lpvBits, const BITMAPINFO *lpbmi, UINT fuColorUse) +{ + int ret; + BITMAPINFOHEADER *bmi; + OutTraceDW("SetDIBitsToDevice: hdc=%x dest=(%d,%d)-(%dx%d) src=(%d,%d) lines=(%d,%d)\n", + hdc, XDest, YDest, dwWidth, dwHeight, XSrc, YSrc, uStartScan, cScanLines); + bmi=(BITMAPINFOHEADER *)&(lpbmi->bmiHeader); + OutTraceDW("SetDIBitsToDevice: BitmapInfo dim=(%dx%d) Planes=%d BPP=%d Compression=%x SizeImage=%x\n", + bmi->biWidth, bmi->biHeight, bmi->biPlanes, bmi->biBitCount, bmi->biCompression, bmi->biSizeImage); -//HBITMAP WINAPI extCreateCompatibleBitmap(HDC hdc, int nWidth, int nHeight) -//{ -// HBITMAP ret; -// OutTraceDW("CreateCompatibleBitmap: hdc=%x size=(%d,%d)\n", -// hdc, nWidth, nHeight); -// -// if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ -// dxw.MapClient(&nWidth, &nHeight); -// OutTraceDW("CreateCompatibleBitmap: fixed size=(%d,%d)\n", nWidth, nHeight); -// } -// -// ret=(*pCreateCompatibleBitmap)(hdc, nWidth, nHeight); -// if(!ret) OutTraceE("CreateCompatibleBitmap: ERROR ret=%x err=%d\n", ret, GetLastError()); -// return ret; -//} + bGDIRecursionFlag = TRUE; // beware: it seems that SetDIBitsToDevice calls SetDIBits internally + if(dxw.IsToRemap(hdc)){ + HDC hTempDc; + HBITMAP hbmPic; + DWORD OrigWidth, OrigHeight; + int OrigXDest, OrigYDest; + OrigWidth=dwWidth; + OrigHeight=dwHeight; + OrigXDest=XDest; + OrigYDest=YDest; + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pSetDIBitsToDevice)(sdc.GetHdc(), XDest, YDest, dwWidth, dwHeight, XSrc, YSrc, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse); + sdc.PutPrimaryDC(hdc, TRUE, XDest, YDest, dwWidth, dwHeight); + bGDIRecursionFlag = FALSE; + return ret; + break; + case GDIMODE_STRETCHED: + // blitting to primary surface !!! + dxw.MapClient(&XDest, &YDest, (int *)&dwWidth, (int *)&dwHeight); + OutTraceDW("SetDIBitsToDevice: fixed dest=(%d,%d)-(%dx%d)\n", XDest, YDest, dwWidth, dwHeight); + if(!(hTempDc=CreateCompatibleDC(hdc))) + OutTraceE("CreateCompatibleDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + // tricky part: CreateCompatibleBitmap is needed to set the dc size, but it has to be performed + // against hdc to set for color depth, then selected (through SelectObject) against the temporary + // dc to assign the needed size and color space to the temporary dc. + if(!(hbmPic=CreateCompatibleBitmap(hdc, OrigWidth, OrigHeight))) + OutTraceE("CreateCompatibleBitmap: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + if(!SelectObject(hTempDc, hbmPic)) + OutTraceE("SelectObject: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + if(!(ret=(*pSetDIBitsToDevice)(hTempDc, 0, 0, OrigWidth, OrigHeight, XSrc, YSrc, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse))) + OutTraceE("SetDIBitsToDevice: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + bGDIRecursionFlag = FALSE; + // v2.02.94: set HALFTONE stretching. Fixes "Celtic Kings Rage of War" + SetStretchBltMode(hdc,HALFTONE); + if(!(ret=(*pGDIStretchBlt)(hdc, XDest, YDest, dwWidth, dwHeight, hTempDc, 0, 0, OrigWidth, OrigHeight, SRCCOPY))) + OutTraceE("StretchBlt: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + if(!(DeleteObject(hbmPic))) // v2.02.32 - avoid resource leakage + OutTraceE("DeleteObject: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + if(!(DeleteDC(hTempDc))) + OutTraceE("DeleteDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + return ret; + break; + case GDIMODE_EMULATED: + int X, Y; + X=XDest+dxw.VirtualOffsetX; + Y=YDest+dxw.VirtualOffsetY; + OutTraceDW("SetDIBitsToDevice: virtual pos=(%d,%d)+(%d+%d)=(%d,%d)\n", + XDest, YDest, dxw.VirtualOffsetX, dxw.VirtualOffsetY, X, Y); + ret=(*pSetDIBitsToDevice)(hdc, X, Y, dwWidth, dwHeight, XSrc, YSrc, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse); + bGDIRecursionFlag = FALSE; + if(!ret || (ret==GDI_ERROR)) OutTraceE("SetDIBitsToDevice: ERROR ret=%x err=%d\n", ret, GetLastError()); + return ret; + default: + break; + } + } + + ret=(*pSetDIBitsToDevice)(hdc, XDest, YDest, dwWidth, dwHeight, XSrc, YSrc, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse); + bGDIRecursionFlag = FALSE; + if(!ret || (ret==GDI_ERROR)) OutTraceE("SetDIBitsToDevice: ERROR ret=%x err=%d\n", ret, GetLastError()); + return ret; +} +#endif + +HBITMAP WINAPI extCreateCompatibleBitmap(HDC hdc, int nWidth, int nHeight) +{ + HBITMAP ret; + OutTraceDW("CreateCompatibleBitmap: hdc=%x size=(%d,%d)\n", + hdc, nWidth, nHeight); + + if (dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pCreateCompatibleBitmap)(sdc.GetHdc(), nWidth, nHeight); + sdc.PutPrimaryDC(hdc, FALSE); + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&nWidth, &nHeight); + OutTraceDW("CreateCompatibleBitmap: fixed size=(%d,%d)\n", nWidth, nHeight); + break; + default: + break; + } + } + + ret=(*pCreateCompatibleBitmap)(hdc, nWidth, nHeight); + if(!ret) OutTraceE("CreateCompatibleBitmap: ERROR ret=%x err=%d\n", ret, GetLastError()); + return ret; +} COLORREF WINAPI extSetPixel(HDC hdc, int X, int Y, COLORREF crColor) { COLORREF ret; OutTraceDW("SetPixel: hdc=%x color=%x point=(%d,%d)\n", hdc, crColor, X, Y); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ - dxw.MapClient(&X, &Y); - OutTraceDW("SetPixel: fixed pos=(%d,%d)\n", X, Y); + if(dxw.IsToRemap(hdc)){ + + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pSetPixel)(sdc.GetHdc(), X, Y, crColor); + sdc.PutPrimaryDC(hdc, TRUE, X, Y, 1, 1); // ???? + return ret; // this returns a COLORREF type + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&X, &Y); + OutTraceDW("SetPixel: fixed pos=(%d,%d)\n", X, Y); + break; + } } ret=(*pSetPixel)(hdc, X, Y, crColor); @@ -1321,14 +2010,48 @@ COLORREF WINAPI extSetPixel(HDC hdc, int X, int Y, COLORREF crColor) return ret; } +BOOL WINAPI extSetPixelV(HDC hdc, int X, int Y, COLORREF crColor) +{ + BOOL ret; + OutTraceDW("SetPixelV: hdc=%x color=%x point=(%d,%d)\n", hdc, crColor, X, Y); + + if(dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pSetPixelV)(sdc.GetHdc(), X, Y, crColor); + sdc.PutPrimaryDC(hdc, TRUE, X, Y, 1, 1); // ???? + return ret; + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&X, &Y); + OutTraceDW("SetPixelV: fixed pos=(%d,%d)\n", X, Y); + break; + } + } + + ret=(*pSetPixelV)(hdc, X, Y, crColor); + return ret; +} + BOOL WINAPI extEllipse(HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect) { int ret; OutTraceDW("Ellipse: hdc=%x rect=(%d,%d)-(%d,%d)\n", hdc, nLeftRect, nTopRect, nRightRect, nBottomRect); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ - dxw.MapClient(&nLeftRect, &nTopRect, &nRightRect, &nBottomRect); - OutTraceDW("Ellipse: fixed dest=(%d,%d)-(%d,%d)\n", nLeftRect, nTopRect, nRightRect, nBottomRect); + if (dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pEllipse)(sdc.GetHdc(),nLeftRect, nTopRect, nRightRect, nBottomRect); + sdc.PutPrimaryDC(hdc, TRUE, nLeftRect, nTopRect, nRightRect-nLeftRect, nBottomRect-nTopRect); + return ret; + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&nLeftRect, &nTopRect, &nRightRect, &nBottomRect); + OutTraceDW("Ellipse: fixed dest=(%d,%d)-(%d,%d)\n", nLeftRect, nTopRect, nRightRect, nBottomRect); + break; + } } ret=(*pEllipse)(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect); @@ -1346,16 +2069,48 @@ BOOL WINAPI extPolygon(HDC hdc, const POINT *lpPoints, int cCount) for(i=0; ix = dxw.VirtualOffsetX; - lpPoint->y = dxw.VirtualOffsetY; - } - dxw.VirtualOffsetX = X; - dxw.VirtualOffsetY = Y; - return TRUE; - } - - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ - dxw.MapClient(&X, &Y); - OutTraceDW("SetViewportOrgEx: fixed pos=(%d,%d)\n", X, Y); - } - - ret=(*pSetViewportOrgEx)(hdc, X, Y, lpPoint); - if(ret && lpPoint) { - OutTraceDW("SetViewportOrgEx: previous ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ - dxw.UnmapClient(lpPoint); - OutTraceDW("SetViewportOrgEx: fixed previous ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); + if(dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_EMULATED: + if(dxw.IsVirtual(hdc)) { + OutTraceDW("SetViewportOrgEx: virtual hdc\n"); + if(lpPoint){ + lpPoint->x = dxw.VirtualOffsetX; + lpPoint->y = dxw.VirtualOffsetY; + } + dxw.VirtualOffsetX = X; + dxw.VirtualOffsetY = Y; + ret = TRUE; + } + else + ret=(*pSetViewportOrgEx)(hdc, X, Y, lpPoint); + break; + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pSetViewportOrgEx)(sdc.GetHdc(), X, Y, lpPoint); + sdc.PutPrimaryDC(hdc, FALSE); + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&X, &Y); + OutTraceDW("SetViewportOrgEx: fixed pos=(%d,%d)\n", X, Y); + ret=(*pSetViewportOrgEx)(hdc, X, Y, lpPoint); + if(ret && lpPoint) { + OutTraceDW("SetViewportOrgEx: previous ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); + dxw.UnmapClient(lpPoint); + OutTraceDW("SetViewportOrgEx: fixed previous ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); + } + break; + default: + ret=(*pSetViewportOrgEx)(hdc, X, Y, lpPoint); + break; } } + else{ + ret=(*pSetViewportOrgEx)(hdc, X, Y, lpPoint); + } + + if(ret && lpPoint) OutTraceDW("SetViewportOrgEx: previous ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); if(!ret) OutTraceE("SetViewportOrgEx: ERROR ret=%x err=%d\n", ret, GetLastError()); return ret; } -BOOL WINAPI extSetViewportExtEx(HDC hdc, int nXExtent, int nYExtent, LPSIZE lpSize) +BOOL WINAPI extSetViewportExtEx(HDC hdc, int X, int Y, LPSIZE lpSize) { BOOL ret; - OutTraceDW("SetViewportExtEx: hdc=%x ext=(%d,%d)\n", hdc, nXExtent, nYExtent); + OutTraceDW("SetViewportExtEx: hdc=%x pos=(%d,%d)\n", hdc, X, Y); - if(dxw.IsVirtual(hdc)) { - OutTraceDW("SetViewportExtEx: virtual hdc\n"); - if(lpSize){ - lpSize->cx = dxw.VirtualExtentX; - lpSize->cy = dxw.VirtualExtentY; - } - dxw.VirtualExtentX = nXExtent; - dxw.VirtualExtentY = nYExtent; - return TRUE; - } - - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ - dxw.MapClient(&nXExtent, &nYExtent); - OutTraceDW("SetViewportExtEx: fixed ext=(%d,%d)\n", nXExtent, nYExtent); - } - - ret=(*pSetViewportExtEx)(hdc, nXExtent, nYExtent, lpSize); - if(ret && lpSize) { - OutTraceDW("SetViewportExtEx: previous ext=(%d,%d)\n", lpSize->cx, lpSize->cy); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ - dxw.UnmapClient((LPPOINT)lpSize); - OutTraceDW("SetViewportExtEx: fixed previous ext=(%d,%d)\n", lpSize->cx, lpSize->cy); + if(dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_EMULATED: + if(dxw.IsVirtual(hdc)) { + OutTraceDW("SetViewportExtEx: virtual hdc\n"); + if(lpSize){ + lpSize->cx = dxw.VirtualExtentX; + lpSize->cy = dxw.VirtualExtentY; + } + dxw.VirtualExtentX = X; + dxw.VirtualExtentY = Y; + ret = TRUE; + } + else + ret=(*pSetViewportExtEx)(hdc, X, Y, lpSize); + break; + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pSetViewportExtEx)(sdc.GetHdc(), X, Y, lpSize); + sdc.PutPrimaryDC(hdc, FALSE); + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&X, &Y); + OutTraceDW("SetViewportExtEx: fixed pos=(%d,%d)\n", X, Y); + ret=(*pSetViewportExtEx)(hdc, X, Y, lpSize); + if(ret && lpSize) { + OutTraceDW("SetViewportExtEx: previous ViewPort=(%d,%d)\n", lpSize->cx, lpSize->cy); + dxw.UnmapClient((LPPOINT)lpSize); + OutTraceDW("SetViewportExtEx: fixed previous ViewPort=(%d,%d)\n", lpSize->cx, lpSize->cy); + } + break; + default: + ret=(*pSetViewportExtEx)(hdc, X, Y, lpSize); + break; } } + else{ + ret=(*pSetViewportExtEx)(hdc, X, Y, lpSize); + } - if(!ret) OutTraceE("SetViewportExtEx: ERROR ret=%x err=%d\n", ret, GetLastError()); + if(ret && lpSize) OutTraceDW("SetViewportOrgEx: previous ViewPort=(%d,%d)\n", lpSize->cx, lpSize->cy); + if(!ret) OutTraceE("SetViewportOrgEx: ERROR ret=%x err=%d\n", ret, GetLastError()); return ret; } @@ -1575,7 +2378,7 @@ BOOL WINAPI extGetViewportOrgEx(HDC hdc, LPPOINT lpPoint) ret=(*pGetViewportOrgEx)(hdc, lpPoint); if(ret) { OutTraceDW("GetViewportOrgEx: ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ + if (dxw.IsToRemap(hdc)){ dxw.UnmapClient(lpPoint); OutTraceDW("GetViewportOrgEx: fixed ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); } @@ -1599,7 +2402,7 @@ BOOL WINAPI extGetViewportExtEx(HDC hdc, LPPOINT lpPoint) ret=(*pGetViewportExtEx)(hdc, lpPoint); if(ret) { OutTraceDW("GetViewportExtEx: ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ + if (dxw.IsToRemap(hdc)){ dxw.UnmapClient(lpPoint); OutTraceDW("GetViewportOrgEx: fixed ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); } @@ -1617,7 +2420,7 @@ BOOL WINAPI extGetWindowOrgEx(HDC hdc, LPPOINT lpPoint) ret=(*pGetWindowOrgEx)(hdc, lpPoint); if(ret) { OutTraceDW("GetWindowOrgEx: ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ + if (dxw.IsToRemap(hdc)){ dxw.UnmapClient(lpPoint); OutTraceDW("GetWindowOrgEx: fixed ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); } @@ -1632,7 +2435,7 @@ BOOL WINAPI extSetWindowOrgEx(HDC hdc, int X, int Y, LPPOINT lpPoint) BOOL ret; OutTraceDW("SetWindowOrgEx: hdc=%x pos=(%d,%d)\n", hdc, X, Y); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ + if (dxw.IsToRemap(hdc)){ dxw.MapClient(&X, &Y); OutTraceDW("SetWindowOrgEx: fixed pos=(%d,%d)\n", X, Y); } @@ -1640,7 +2443,7 @@ BOOL WINAPI extSetWindowOrgEx(HDC hdc, int X, int Y, LPPOINT lpPoint) ret=(*pSetWindowOrgEx)(hdc, X, Y, lpPoint); if(ret && lpPoint) { OutTraceDW("SetWindowOrgEx: previous ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ + if (dxw.IsToRemap(hdc)){ dxw.UnmapClient(lpPoint); OutTraceDW("SetWindowOrgEx: fixed previous ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); } @@ -1654,7 +2457,7 @@ BOOL WINAPI extSetWindowExtEx(HDC hdc, int X, int Y, LPPOINT lpPoint) BOOL ret; OutTraceDW("SetWindowExtEx: hdc=%x pos=(%d,%d)\n", hdc, X, Y); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ + if (dxw.IsToRemap(hdc)){ dxw.MapClient(&X, &Y); OutTraceDW("SetWindowExtEx: fixed pos=(%d,%d)\n", X, Y); } @@ -1662,7 +2465,7 @@ BOOL WINAPI extSetWindowExtEx(HDC hdc, int X, int Y, LPPOINT lpPoint) ret=(*pSetWindowExtEx)(hdc, X, Y, lpPoint); if(ret && lpPoint) { OutTraceDW("SetWindowExtEx: previous ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ + if (dxw.IsToRemap(hdc)){ dxw.UnmapClient(lpPoint); OutTraceDW("SetWindowExtEx: fixed previous ViewPort=(%d,%d)\n", lpPoint->x, lpPoint->y); } @@ -1679,8 +2482,21 @@ BOOL WINAPI extGetCurrentPositionEx(HDC hdc, LPPOINT lpPoint) ret=(*pGetCurrentPositionEx)(hdc, lpPoint); if(ret) { OutTraceDW("GetCurrentPositionEx: pos=(%d,%d)\n", lpPoint->x, lpPoint->y); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ - dxw.UnmapClient(lpPoint); + if (dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_STRETCHED: + dxw.UnmapClient(lpPoint); + break; + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pGetCurrentPositionEx)(sdc.GetHdc(), lpPoint); + sdc.PutPrimaryDC(hdc, FALSE); + return ret; + break; + case GDIMODE_EMULATED: + default: + break; + } OutTraceDW("GetCurrentPositionEx: fixed pos=(%d,%d)\n", lpPoint->x, lpPoint->y); } } @@ -1834,6 +2650,7 @@ extern BOOL gFixed; BOOL WINAPI extExtTextOutA(HDC hdc, int X, int Y, UINT fuOptions, const RECT *lprc, LPCSTR lpString, UINT cbCount, const INT *lpDx) { RECT rc; + BOOL ret; if(IsTraceDW){ char sRect[81]; if(lprc) sprintf(sRect, "(%d,%d)-(%d,%d)", lprc->left, lprc->top, lprc->right, lprc->bottom); @@ -1841,10 +2658,28 @@ BOOL WINAPI extExtTextOutA(HDC hdc, int X, int Y, UINT fuOptions, const RECT *lp OutTrace("ExtTextOutA: hdc=%x pos=(%d,%d) String=\"%s\" rect=%s\n", hdc, X, Y, lpString, sRect); } - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc)) && !gFixed){ - dxw.MapClient(&X, &Y); - if(lprc) dxw.MapClient(&rc); - OutTraceDW("ExtTextOutA: fixed pos=(%d,%d)\n", X, Y); + if (dxw.IsToRemap(hdc) && !gFixed){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pExtTextOutA)(sdc.GetHdc(), X, Y, fuOptions, lprc, lpString, cbCount, lpDx); + if(lprc){ + rc = *lprc; + sdc.PutPrimaryDC(hdc, TRUE, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top); + } + else + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&X, &Y); + if(lprc) { + rc = *lprc; + dxw.MapClient(&rc); + } + OutTraceDW("ExtTextOutA: fixed pos=(%d,%d)\n", X, Y); + break; + } } if(lprc) return (*pExtTextOutA)(hdc, X, Y, fuOptions, &rc, lpString, cbCount, lpDx); @@ -1855,6 +2690,7 @@ BOOL WINAPI extExtTextOutA(HDC hdc, int X, int Y, UINT fuOptions, const RECT *lp BOOL WINAPI extExtTextOutW(HDC hdc, int X, int Y, UINT fuOptions, const RECT *lprc, LPCWSTR lpString, UINT cbCount, const INT *lpDx) { RECT rc; + BOOL ret; if(IsTraceDW){ char sRect[81]; if(lprc) sprintf(sRect, "(%d,%d)-(%d,%d)", lprc->left, lprc->top, lprc->right, lprc->bottom); @@ -1862,10 +2698,28 @@ BOOL WINAPI extExtTextOutW(HDC hdc, int X, int Y, UINT fuOptions, const RECT *lp OutTrace("ExtTextOutW: hdc=%x pos=(%d,%d) String=\"%ls\" rect=%s\n", hdc, X, Y, lpString, sRect); } - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc)) && !gFixed){ - dxw.MapClient(&X, &Y); - if(lprc) dxw.MapClient(&rc); - OutTraceDW("ExtTextOutW: fixed pos=(%d,%d)\n", X, Y); + if (dxw.IsToRemap(hdc) && !gFixed){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pExtTextOutW)(sdc.GetHdc(), X, Y, fuOptions, lprc, lpString, cbCount, lpDx); + if(lprc){ + rc = *lprc; + sdc.PutPrimaryDC(hdc, TRUE, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top); + } + else + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&X, &Y); + if(lprc) { + rc = *lprc; + dxw.MapClient(&rc); + } + OutTraceDW("ExtTextOutW: fixed pos=(%d,%d)\n", X, Y); + break; + } } if(lprc) return (*pExtTextOutW)(hdc, X, Y, fuOptions, &rc, lpString, cbCount, lpDx); @@ -1949,3 +2803,411 @@ DWORD WINAPI extGetRegionData(HRGN hRgn, DWORD dwCount, LPRGNDATA lpRgnData) return ret; } #endif + +int WINAPI extOffsetRgn(HRGN hrgn, int nXOffset, int nYOffset) +{ + OutTraceDW("OffsetRgn(hrgn=%x nXOffset=%d nYOffset=%d\n", hrgn, nXOffset, nYOffset); + + if(dxw.IsFullScreen()){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_STRETCHED: + dxw.MapClient(&nXOffset, &nYOffset); + OutTraceDW("OffsetRgn: fixed STRETCHED offset=(%d,%d)\n", nXOffset, nYOffset); + break; + default: + break; + } + } + + return (*pOffsetRgn)(hrgn, nXOffset, nYOffset); +} + +COLORREF WINAPI extGetPixel(HDC hdc, int nXPos, int nYPos) +{ + COLORREF ret; + OutTraceDW("CreateDIBitmap: hdc=%x\n", hdc); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pGetPixel)(sdc.GetHdc(), nXPos, nYPos); + sdc.PutPrimaryDC(hdc, FALSE); + return ret; + break; + default: + // to do ..... + break; + } + } + + ret=(*pGetPixel)(hdc, nXPos, nYPos); + if(!ret) OutTraceE("CreateDIBitmap ERROR: err=%d\n", GetLastError()); + return ret;} + +BOOL WINAPI extPlgBlt(HDC hdcDest, const POINT *lpPoint, HDC hdcSrc, int nXSrc, int nYSrc, int nWidth, int nHeight, HBITMAP hbmMask, int xMask, int yMask) +{ + MessageBox(0, "PlgBlt", "DxWnd", MB_OK); + return (COLORREF)0; +} + +BOOL WINAPI extChord(HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nXRadial1, int nYRadial1, int nXRadial2, int nYRadial2) +{ + MessageBox(0, "Chord", "DxWnd", MB_OK); + return (COLORREF)0; +} + +BOOL WINAPI extPolyTextOutA(HDC hdc, const POLYTEXTA *pptxt, int cStrings) +{ + MessageBox(0, "PolyTextOutA", "DxWnd", MB_OK); + return TRUE; +} + +BOOL WINAPI extPolyTextOutW(HDC hdc, const POLYTEXTW *pptxt, int cStrings) +{ + MessageBox(0, "PolyTextOutW", "DxWnd", MB_OK); + return TRUE; +} + +HBITMAP WINAPI extCreateDIBitmap(HDC hdc, BITMAPINFOHEADER *lpbmih, DWORD fdwInit, const VOID *lpbInit, const BITMAPINFO *lpbmi, UINT fuUsage) +{ + HBITMAP ret; + OutTraceDW("CreateDIBitmap: hdc=%x\n", hdc); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pCreateDIBitmap)(sdc.GetHdc(), lpbmih, fdwInit, lpbInit, lpbmi, fuUsage); + sdc.PutPrimaryDC(hdc, FALSE); + return ret; + break; + default: + break; + } + } + + ret = (*pCreateDIBitmap)(hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage); + if(!ret) OutTraceE("CreateDIBitmap ERROR: err=%d\n", GetLastError()); + return ret; +} + +HBITMAP WINAPI extCreateDIBSection(HDC hdc, const BITMAPINFO *pbmi, UINT iUsage, VOID **ppvBits, HANDLE hSection, DWORD dwOffset) +{ + HBITMAP ret; + OutTraceDW("CreateDIBitmap: hdc=%x\n", hdc); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pCreateDIBSection)(sdc.GetHdc(), pbmi, iUsage, ppvBits, hSection, dwOffset); + sdc.PutPrimaryDC(hdc, FALSE); + return ret; + break; + default: + break; + } + } + + ret=(*pCreateDIBSection)(hdc, pbmi, iUsage, ppvBits, hSection, dwOffset); + if(!ret) OutTraceE("CreateDIBitmap ERROR: err=%d\n", GetLastError()); + return ret; +} + +HBITMAP WINAPI extCreateDiscardableBitmap(HDC hdc, int nWidth, int nHeight) +{ + HBITMAP ret; + OutTraceDW("CreateDiscardableBitmap: hdc=%x size=(%dx%d)\n", hdc, nWidth, nHeight); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pCreateDiscardableBitmap)(sdc.GetHdc(), nWidth, nHeight); + sdc.PutPrimaryDC(hdc, FALSE); + return ret; + break; + default: + break; + } + } + + ret=(*pCreateDiscardableBitmap)(hdc, nWidth, nHeight); + if(!ret) OutTraceE("CreateDiscardableBitmap ERROR: err=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extExtFloodFill(HDC hdc, int nXStart, int nYStart, COLORREF crColor, UINT fuFillType) +{ + BOOL ret; + OutTraceDW("ExtFloodFill: hdc=%x pos=(%d,%d)\n", hdc, nXStart, nYStart); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pExtFloodFill)(sdc.GetHdc(), nXStart, nYStart, crColor, fuFillType); + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + default: + break; + } + } + + ret=(*pExtFloodFill)(hdc, nXStart, nYStart, crColor, fuFillType); + if(!ret) OutTraceE("ExtFloodFill ERROR: err=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extGdiAlphaBlend(HDC hdcDest, int xoriginDest, int yoriginDest, int wDest, int hDest, HDC hdcSrc, int xoriginSrc, int yoriginSrc, int wSrc, int hSrc, BLENDFUNCTION ftn) +{ + // to be handled the 4 flux cases ..... + _Warn("GdiAlphaBlend"); + return TRUE; +} + +BOOL WINAPI extGdiGradientFill(HDC hdc, PTRIVERTEX pVertex, ULONG nVertex, PVOID pMesh, ULONG nMesh, ULONG ulMode) +{ + _Warn("GdiGradientFill"); + return TRUE; +} + +BOOL WINAPI extGdiTransparentBlt(HDC hdcDest, int xoriginDest, int yoriginDest, int wDest, int hDest, + HDC hdcSrc, int xoriginSrc, int yoriginSrc, int wSrc, int hSrc, UINT crTransparent) +{ + // to be handled the 4 flux cases ..... + _Warn("GdiTransparentBlt"); + return TRUE; +} + +BOOL WINAPI extPie(HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nXRadial1, int nYRadial1, int nXRadial2, int nYRadial2) +{ + BOOL ret; + OutTraceDW("Pie: hdc=%x rect=(%d,%d)-(%d,%d)\n", hdc, nLeftRect, nTopRect, nRightRect, nBottomRect); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pPie)(sdc.GetHdc(), nLeftRect, nTopRect, nRightRect, nBottomRect, nXRadial1, nYRadial1, nXRadial2, nYRadial2); + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + default: + break; + } + } + + ret=(*pPie)(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect, nXRadial1, nYRadial1, nXRadial2, nYRadial2); + if(!ret) OutTraceE("Pie ERROR: err=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extAngleArc(HDC hdc, int X, int Y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle) +{ + BOOL ret; + OutTraceDW("AngleArc: hdc=%x pos=(%d,%d)\n", hdc, X, Y); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pAngleArc)(sdc.GetHdc(), X, Y, dwRadius, eStartAngle, eSweepAngle); + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + default: + break; + } + } + + ret=(*pAngleArc)(hdc, X, Y, dwRadius, eStartAngle, eSweepAngle); + if(!ret) OutTraceE("AngleArc ERROR: err=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extPolyPolyline(HDC hdc, const POINT *lppt, const DWORD *lpdwPolyPoints, DWORD cCount) +{ + BOOL ret; + OutTraceDW("PolyPolyline: hdc=%x\n", hdc); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pPolyPolyline)(sdc.GetHdc(), lppt, lpdwPolyPoints, cCount); + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + default: + break; + } + } + + ret=(*pPolyPolyline)(hdc, lppt, lpdwPolyPoints, cCount); + if(!ret) OutTraceE("PolyPolyline ERROR: err=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extFillRgn(HDC hdc, HRGN hrgn, HBRUSH hbr) +{ + BOOL ret; + OutTraceDW("FillRgn: hdc=%x\n", hdc); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pFillRgn)(sdc.GetHdc(), hrgn, hbr); + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + default: + break; + } + } + + ret=(*pFillRgn)(hdc, hrgn, hbr); + if(!ret) OutTraceE("FillRgn ERROR: err=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extFrameRgn(HDC hdc, HRGN hrgn, HBRUSH hbr, int nWidth, int nHeight) +{ + BOOL ret; + OutTraceDW("FrameRgn: hdc=%x\n", hdc); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pFrameRgn)(sdc.GetHdc(), hrgn, hbr, nWidth, nHeight); + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + default: + break; + } + } + + ret=(*pFrameRgn)(hdc, hrgn, hbr, nWidth, nHeight); + if(!ret) OutTraceE("FrameRgn ERROR: err=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extInvertRgn(HDC hdc, HRGN hrgn) +{ + BOOL ret; + OutTraceDW("InvertRgn: hdc=%x hrgn=%x\n", hdc, hrgn); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pInvertRgn)(sdc.GetHdc(), hrgn); + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + default: + break; + } + } + + ret=(*pInvertRgn)(hdc, hrgn); + if(!ret) OutTraceE("InvertRgn ERROR: err=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extPaintRgn(HDC hdc, HRGN hrgn) +{ + BOOL ret; + OutTraceDW("PaintRgn: hdc=%x hrgn=%x\n", hdc, hrgn); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pPaintRgn)(sdc.GetHdc(), hrgn); + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + default: + break; + } + } + + ret=(*pPaintRgn)(hdc, hrgn); + if(!ret) OutTraceE("PaintRgn ERROR: err=%d\n", GetLastError()); + return ret; +} + +int WINAPI extSetMapMode(HDC hdc, int fnMapMode) +{ + int ret; + OutTraceDW("SetMapMode: hdc=%x fnMapMode=%x\n", hdc, fnMapMode); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pSetMapMode)(sdc.GetHdc(), fnMapMode); + sdc.PutPrimaryDC(hdc, FALSE); + return ret; + break; + default: + break; + } + } + + ret=(*pSetMapMode)(hdc, fnMapMode); + if(!ret) OutTraceE("SetMapMode ERROR: err=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extRoundRect(HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nWidth, int nHeight) +{ + int ret; + OutTraceDW("RoundRect: hdc=%x rect=(%d,%d)-(%d,%d) ellipse=(%dx%d)\n", hdc, nLeftRect, nTopRect, nRightRect, nBottomRect, nWidth, nHeight); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pRoundRect)(sdc.GetHdc(), nLeftRect, nTopRect, nRightRect, nBottomRect, nWidth, nHeight); + sdc.PutPrimaryDC(hdc, TRUE, nLeftRect, nTopRect, nRightRect, nBottomRect); + return ret; + break; + default: + break; + } + } + + ret=(*pRoundRect)(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect, nWidth, nHeight); + if(!ret) OutTraceE("RoundRect ERROR: err=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extPolyPolygon(HDC hdc, const POINT *lpPoints, const INT *lpPolyCounts, int nCount) +{ + BOOL ret; + OutTraceDW("PolyPolygon: hdc=%x\n", hdc); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pPolyPolygon)(sdc.GetHdc(), lpPoints, lpPolyCounts, nCount); + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + default: + break; + } + } + + ret=(*pPolyPolygon)(hdc, lpPoints, lpPolyCounts, nCount); + if(!ret) OutTraceE("PolyPolygon ERROR: err=%d\n", GetLastError()); + return ret; +} diff --git a/dll/hd3d.cpp b/dll/hd3d.cpp index 308259a..740c81d 100644 --- a/dll/hd3d.cpp +++ b/dll/hd3d.cpp @@ -20,6 +20,8 @@ extern void D3D9TextureHandling(void *, int); extern void D3D8TextureHandling(void *, int); +void *lpD3DActiveDevice = NULL; + typedef HRESULT (WINAPI *QueryInterface_Type)(void *, REFIID riid, void** ppvObj); // D3D8/9 API @@ -212,6 +214,7 @@ typedef HRESULT (WINAPI *SetTexture9_Type)(void *, DWORD, void *); //typedef ULONG (WINAPI *CreateRenderTarget8_Type)(void *, UINT, UINT, D3DFORMAT, D3DMULTISAMPLE_TYPE, BOOL, IDirect3DSurface8**); typedef ULONG (WINAPI *CreateRenderTarget8_Type)(void *, UINT, UINT, D3DFORMAT, D3DMULTISAMPLE_TYPE, BOOL, void**); +typedef ULONG (WINAPI *CreateRenderTarget9_Type)(void *, UINT, UINT, D3DFORMAT, D3DMULTISAMPLE_TYPE, BOOL, void**); typedef ULONG (WINAPI *BeginScene_Type)(void *); typedef ULONG (WINAPI *EndScene_Type)(void *); @@ -250,6 +253,7 @@ BOOL WINAPI voidDisableD3DSpy(void); //ULONG WINAPI extCreateRenderTarget8(void *, UINT, UINT, D3DFORMAT, D3DMULTISAMPLE_TYPE, BOOL, IDirect3DSurface8**); ULONG WINAPI extCreateRenderTarget8(void *, UINT, UINT, D3DFORMAT, D3DMULTISAMPLE_TYPE, BOOL, void**); +ULONG WINAPI extCreateRenderTarget9(void *, UINT, UINT, D3DFORMAT, D3DMULTISAMPLE_TYPE, BOOL, void**); ULONG WINAPI extBeginScene8(void *); ULONG WINAPI extEndScene8(void *); ULONG WINAPI extBeginScene9(void *); @@ -291,6 +295,7 @@ SetGammaRamp_Type pSetGammaRamp = 0; GetGammaRamp_Type pGetGammaRamp = 0; CreateRenderTarget8_Type pCreateRenderTarget8 = 0; +CreateRenderTarget9_Type pCreateRenderTarget9 = 0; BeginScene_Type pBeginScene8 = 0; EndScene_Type pEndScene8 = 0; BeginScene_Type pBeginScene9 = 0; @@ -540,6 +545,7 @@ void HookD3DDevice9(void** ppD3Ddev9) SetHook((void *)(**(DWORD **)ppD3Ddev9 + 124), extUpdateTexture, (void **)&pUpdateTexture, "UpdateTexture(D9)"); #endif + //SetHook((void *)(**(DWORD **)ppD3Ddev9 + 112), extCreateRenderTarget9, (void **)&pCreateRenderTarget9, "CreateRenderTarget(D9)"); SetHook((void *)(**(DWORD **)ppD3Ddev9 + 164), extBeginScene9, (void **)&pBeginScene9, "BeginScene(D9)"); SetHook((void *)(**(DWORD **)ppD3Ddev9 + 168), extEndScene9, (void **)&pEndScene9, "EndScene(D9)"); //SetHook((void *)(**(DWORD **)ppD3Ddev9 +188), extSetViewport, (void **)&pSetViewport, "SetViewport(D9)"); @@ -1153,6 +1159,7 @@ HRESULT WINAPI extCreateDevice(void *lpd3d, UINT adapter, D3DDEVTYPE devicetype, return res; } OutTraceD3D("SUCCESS! device=%x\n", *ppd3dd); + lpD3DActiveDevice = *ppd3dd; if(dwD3DVersion == 8){ HookD3DDevice8(ppd3dd); @@ -1259,6 +1266,7 @@ HRESULT WINAPI extCreateDeviceEx(void *lpd3d, UINT adapter, D3DDEVTYPE devicetyp return res; } OutTraceD3D("SUCCESS!\n"); + lpD3DActiveDevice = *ppd3dd; HookD3DDevice9(ppd3dd); diff --git a/dll/hddraw.h b/dll/hddraw.h index d5fc7aa..2958706 100644 --- a/dll/hddraw.h +++ b/dll/hddraw.h @@ -5,6 +5,7 @@ typedef HRESULT (WINAPI *DirectDrawCreateEx_Type)(GUID *, LPDIRECTDRAW *, REFIID typedef HRESULT (WINAPI *DirectDrawEnumerate_Type)(LPDDENUMCALLBACK, LPVOID); typedef HRESULT (WINAPI *DirectDrawEnumerateEx_Type)(LPDDENUMCALLBACKEX, LPVOID, DWORD); typedef HRESULT (WINAPI *DirectDrawCreateClipper_Type)(DWORD, LPDIRECTDRAWCLIPPER *, IUnknown *); +typedef void (WINAPI *HandleDDThreadLock_Type)(void); typedef HDC (WINAPI *GDIGetDC_Type)(HWND); typedef int (WINAPI *GDIReleaseDC_Type)(HWND, HDC); diff --git a/dll/kernel32.cpp b/dll/kernel32.cpp index 65d1af9..3e4fae3 100644 --- a/dll/kernel32.cpp +++ b/dll/kernel32.cpp @@ -9,6 +9,7 @@ //#undef IsTraceDW //#define IsTraceDW TRUE #define LOCKINJECTIONTHREADS +#define TRYFATNAMES TRUE BOOL WINAPI extCheckRemoteDebuggerPresent(HANDLE, PBOOL); LPVOID WINAPI extVirtualAlloc(LPVOID, SIZE_T, DWORD, DWORD); @@ -792,6 +793,7 @@ HANDLE WINAPI extCreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwS DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { HANDLE ret; + int err=0; OutTraceDW("CreateFile: FileName=%s DesiredAccess=%x SharedMode=%x Disposition=%x Flags=%x\n", lpFileName, dwDesiredAccess, dwShareMode, dwCreationDisposition, dwFlagsAndAttributes); @@ -809,8 +811,29 @@ HANDLE WINAPI extCreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwS if(ret && (ret != (HANDLE)INVALID_SET_FILE_POINTER)) OutTrace("CreateFile: ret=%x\n", ret); else - OutTrace("CreateFile ERROR: err=%d\n", GetLastError()); + OutTrace("CreateFile ERROR: err=%d\n", err=GetLastError()); } + +#if 0 + if(TRYFATNAMES && (!ret) && (err==ERROR_FILE_NOT_FOUND)){ + char ShortPath[MAX_PATH+1]; + int iLastBackSlash, iFnameLength; + char *sFileName; + strncpy(ShortPath, lpFileName, MAX_PATH); + iLastBackSlash = -1; + for(size_t i=0; i 8){ + sFileName[6] = '~'; + sFileName[7] = '1'; + strcpy(&sFileName[8], &sFileName[iFnameLength]); + } + OutTrace("CreateFile: try FAT path=\"%s\"\n", ShortPath); + ret=(*pCreateFile)(ShortPath, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); + } +#endif + return ret; } diff --git a/dll/msims32.cpp b/dll/msims32.cpp new file mode 100644 index 0000000..5aabbca --- /dev/null +++ b/dll/msims32.cpp @@ -0,0 +1,74 @@ +#define _CRT_SECURE_NO_WARNINGS + +#include "dxwnd.h" +#include "dxwcore.hpp" +#include "syslibs.h" +#include "hddraw.h" +#include "dxhook.h" +#include "dxhelper.h" +#include "shareddc.hpp" + +#include "stdio.h" + +static BOOL bGDIRecursionFlag = FALSE; + +#define _Warn(s) MessageBox(0, s, "to do", MB_ICONEXCLAMATION) + +typedef BOOL (WINAPI *AlphaBlend_Type)(HDC hdcDest, int xoriginDest, int yoriginDest, int wDest, int hDest, HDC hdcSrc, int xoriginSrc, int yoriginSrc, int wSrc, int hSrc, BLENDFUNCTION ftn); +AlphaBlend_Type pAlphaBlend = NULL; +BOOL WINAPI extAlphaBlend(HDC hdcDest, int xoriginDest, int yoriginDest, int wDest, int hDest, HDC hdcSrc, int xoriginSrc, int yoriginSrc, int wSrc, int hSrc, BLENDFUNCTION ftn); + +typedef BOOL (WINAPI *GradientFill_Type)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG); +GradientFill_Type pGradientFill = NULL; +BOOL WINAPI extGradientFill(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG); + +typedef BOOL (WINAPI *TransparentBlt_Type)(HDC, int, int, int, int, HDC, int, int, int, int, UINT); +TransparentBlt_Type pTransparentBlt = NULL; +BOOL WINAPI extTransparentBlt(HDC, int, int, int, int, HDC, int, int, int, int, UINT); + +static HookEntry_Type Hooks[]={ + + {HOOK_IAT_CANDIDATE, "AlphaBlend", (FARPROC)NULL, (FARPROC *)&pAlphaBlend, (FARPROC)extAlphaBlend}, + {HOOK_IAT_CANDIDATE, "GradientFill", (FARPROC)NULL, (FARPROC *)&pGradientFill, (FARPROC)extGradientFill}, + {HOOK_IAT_CANDIDATE, "TransparentBlt", (FARPROC)NULL, (FARPROC *)&pTransparentBlt, (FARPROC)extTransparentBlt}, + {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator +}; + +static char *libname = "msimg32.dll"; + +void HookMSIMG32Init() +{ + HookLibInit(Hooks); +} + +void HookMSIMG32(HMODULE module) +{ + HookLibrary(module, Hooks, libname); +} + +FARPROC Remap_MSIMG32_ProcAddress(LPCSTR proc, HMODULE hModule) +{ + FARPROC addr; + + if(addr=RemapLibrary(proc, hModule, Hooks)) return addr; + return NULL; +} + +BOOL WINAPI extAlphaBlend(HDC hdcDest, int xoriginDest, int yoriginDest, int wDest, int hDest, HDC hdcSrc, int xoriginSrc, int yoriginSrc, int wSrc, int hSrc, BLENDFUNCTION ftn) +{ + _Warn("AlphaBlend"); + return TRUE; +} + +BOOL WINAPI extGradientFill(HDC hdc, PTRIVERTEX pVertex, ULONG nVertex, PVOID pMesh, ULONG nMesh, ULONG ulMode) +{ + _Warn("GradientFill"); + return TRUE; +} + +BOOL WINAPI extTransparentBlt(HDC hdcDest, int xoriginDest, int yoriginDest, int wDest, int hDest, + HDC hdcSrc, int xoriginSrc, int yoriginSrc, int wSrc, int hSrc, UINT crTransparent) +{ + _Warn("TransparentBlt"); + return TRUE; +} diff --git a/dll/shareddc.cpp b/dll/shareddc.cpp new file mode 100644 index 0000000..eb40911 --- /dev/null +++ b/dll/shareddc.cpp @@ -0,0 +1,461 @@ +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include "dxwnd.h" +#include "dxwcore.hpp" +#include "syslibs.h" +#include "dxhelper.h" +#include "resource.h" +#include "hddraw.h" +#include "shareddc.hpp" + +//#define D3D9TRY +#define SHAREDDCDEBUG FALSE +#if SHAREDDCDEBUG +#define _Warn(s) {char cap[80]; sprintf(cap, "Warn at %d", __LINE__); MessageBox(NULL, (s), cap, MB_OK);} +#else +#define _Warn(s) +#endif + + +extern ReleaseDC_Type pReleaseDC; +extern HandleDDThreadLock_Type pReleaseDDThreadLock; +extern GetDC_Type pGetDC; + +/*---------------------------------------------------------------------------------+ +| | +| Constructor, Desctructor | +| | ++---------------------------------------------------------------------------------*/ + +dxwSDC::dxwSDC() +{ + OutTraceB("dxwSDC::dxwSDC: Initialize\n"); + PrimaryDC = NULL; + lpDDSPrimary = NULL; + LastScreenWidth = LastScreenHeight = 0; + LastHDC = NULL; + CurrenthWnd = NULL; +} + +dxwSDC::~dxwSDC() +{ + OutTraceB("dxwSDC::~dxwSDC: Destroy\n"); +} + +/*---------------------------------------------------------------------------------+ +| | +| GetPrimaryDC: builds a suitable DC to write to, according to the input DC | +| | ++---------------------------------------------------------------------------------*/ + +static IDirect3DSurface9 *pDestSurface = NULL; + +HDC dxwSDC::GetPrimaryDC(HDC hdc) +{ + HRESULT res; + extern HandleDDThreadLock_Type pReleaseDDThreadLock; + extern GetDC_Type pGetDC; + extern ReleaseDC_Type pReleaseDC; + extern void *lpD3DActiveDevice; + + OutTraceB("dxwSDC::GetPrimaryDC: hdc=%x\n", hdc); +#ifdef D3D9TRY + if(lpD3DActiveDevice){ + // search for D3D first + //RECT client; + //(*pGetClientRect)(dxw.GethWnd(), &client); + //if(pDestSurface == NULL){ + // //res=((IDirect3DDevice9 *)lpD3DActiveDevice)->CreateOffscreenPlainSurface(ScreenWidth, ScreenHeight, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, &pDestSurface, NULL); + // //res=((IDirect3DDevice9 *)lpD3DActiveDevice)->CreateOffscreenPlainSurface(dxw.GetScreenWidth(), dxw.GetScreenHeight(), D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, &pDestSurface, NULL); + // res=((IDirect3DDevice9 *)lpD3DActiveDevice)->CreateOffscreenPlainSurface(client.right, client.bottom, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, &pDestSurface, NULL); + // if(res){ + // OutTraceE("dxwSDC::CreateOffscreenPlainSurface: ERROR err=%x(%s) at=%d\n", res, ExplainDDError(res), __LINE__); + // return NULL; + // _Warn("CreateOffscreenPlainSurface ERROR"); + // } + //} + //res=((IDirect3DDevice9 *)lpD3DActiveDevice)->GetFrontBufferData(1, pDestSurface); + //if(res){ + // OutTraceE("GetFrontBufferData: ERROR err=%x(%s) at=%d\n", res, ExplainDDError(res), __LINE__); + // _Warn("GetFrontBufferData ERROR"); + //} + IDirect3DSurface9 *pRenderSurface; + res=((IDirect3DDevice9 *)lpD3DActiveDevice)->GetRenderTarget(0, &pRenderSurface); + if(res){ + OutTraceE("d3d9::GetRenderTarget: ERROR err=%x(%s) at=%d\n", res, ExplainDDError(res), __LINE__); + _Warn("d3d9::GetRenderTarget ERROR"); + } + //res=((IDirect3DDevice9 *)lpD3DActiveDevice)->GetRenderTargetData(pRenderSurface, pDestSurface); + //if(res){ + // OutTraceE("d3d9::GetRenderTargetData: ERROR err=%x(%s) at=%d\n", res, ExplainDDError(res), __LINE__); + // _Warn("d3d9::GetRenderTargetData ERROR"); + //} + //res=pDestSurface->GetDC(&PrimaryDC); + res=pRenderSurface->GetDC(&PrimaryDC); + if(res){ + OutTraceE("d3d9::GetDC: ERROR err=%x(%s) at=%d\n", res, ExplainDDError(res), __LINE__); + //_Warn("d3d9::GetDC ERROR"); + VirtualSurfaceType = VIRTUAL_ON_D3D; + return NULL; + } + VirtualSurfaceType = VIRTUAL_ON_D3D; + } + else { +#else + { +#endif + // else look for ddraw + //if(pReleaseDDThreadLock)(*pReleaseDDThreadLock)(); + lpDDSPrimary = dxwss.GetPrimarySurface(); + if (lpDDSPrimary) { + if(pReleaseDDThreadLock)(*pReleaseDDThreadLock)(); + res=((*pGetDC)(lpDDSPrimary, &PrimaryDC)); + while((PrimaryDC == NULL) && lpDDSPrimary) { + OutTraceB("dxwSDC::GetPrimaryDC: found primary surface with no DC, unref lpdds=%x\n", lpDDSPrimary); + dxwss.UnrefSurface(lpDDSPrimary); + lpDDSPrimary = dxwss.GetPrimarySurface(); + if (lpDDSPrimary) (*pGetDC)(lpDDSPrimary, &PrimaryDC); + } + if (!PrimaryDC) { + _Warn("No primary DC"); + OutTraceB("dxwSDC::GetPrimaryDC: no ddraw primary DC\n"); + return NULL; + } + // avoid double Getdc on same hdc and lock + // if(PrimaryDC == hdc) (*pReleaseDC)(lpDDSPrimary, PrimaryDC); + OutTraceB("dxwSDC::GetPrimaryDC: ddraw PrimaryDC=%x\n", PrimaryDC); + VirtualSurfaceType = VIRTUAL_ON_DDRAW; + } + else { + // finally, search GDI DC + PrimaryDC = (*pGDIGetDC)(dxw.GethWnd()); + if (!PrimaryDC) { + _Warn("No window DC"); + OutTraceB("dxwSDC::GetPrimaryDC: no windows DC\n"); + return NULL; + } + OutTraceB("dxwSDC::GetPrimaryDC: gdi PrimaryDC=%x\n", PrimaryDC); + VirtualSurfaceType = VIRTUAL_ON_WINDOW; + } + } + + // whenever the hdc changes, rebuild the virtual DC + if(hdc != LastHDC) do { + LastHDC = hdc; + RECT client; + if(VirtualHDC){ + //(*pGDIReleaseDC)(dxw.GethWnd(), VirtualHDC); + DeleteObject(VirtualHDC); + } + + if(!(VirtualHDC=(*pGDICreateCompatibleDC)(PrimaryDC))){ + OutTraceE("CreateCompatibleDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + _Warn("CreateCompatibleDC ERROR"); + break; + } + + if(!(CurrenthWnd = WindowFromDC(hdc))){ + OutTraceE("dxwSDC::GetPrimaryDC: WindowFromDC ERROR err=%d at=%d\n", GetLastError(), __LINE__); + _Warn("WindowFromDC ERROR"); + break; + } + + if(!(*pGetClientRect)(CurrenthWnd, &client)){ + OutTraceE("dxwSDC::GetPrimaryDC: GetClietError ERROR err=%d at=%d\n", GetLastError(), __LINE__); + _Warn("GetClietError ERROR"); + break; + } + + dxw.UnmapClient(&client); + ScreenWidth = client.right; + ScreenHeight = client.bottom; + + OutTraceB("dxwSDC::GetPrimaryDC: VirtualHDC INITIALIZE size=(%dx%d)\n", LastScreenWidth, LastScreenHeight); + + if(!(VirtualPic=(*pCreateCompatibleBitmap)(PrimaryDC, ScreenWidth, ScreenHeight))){ + OutTraceE("dxwSDC::GetPrimaryDC: CreateCompatibleBitmap ERROR err=%d at=%d\n", GetLastError(), __LINE__); + _Warn("CreateCompatibleBitmap ERROR"); + } + + if(!SelectObject(VirtualHDC, VirtualPic)){ + OutTraceE("dxwSDC::GetPrimaryDC: SelectObject ERROR err=%d at=%d\n", GetLastError(), __LINE__); + _Warn("SelectObject ERROR"); + } + + DeleteObject(VirtualPic); + VirtualPic = 0; + } while(0); + + if(CurrenthWnd && CurrenthWnd!=dxw.GethWnd()){ + POINT zero1 = {0, 0}; + POINT zero2 = {0, 0}; + (*pClientToScreen)(CurrenthWnd, &zero1); + (*pClientToScreen)(dxw.GethWnd(), &zero2); + WinOffset.x = zero1.x - zero2.x; + WinOffset.y = zero1.y - zero2.y; + VirtualOffset = WinOffset; + dxw.UnmapClient(&VirtualOffset); + OutTraceB("dxwSDC::GetPrimaryDC: WinOffset=(%d,%d)->(%d,%d)\n", WinOffset.x, WinOffset.y, VirtualOffset.x, VirtualOffset.y); + } + else { + WinOffset.x = 0; + WinOffset.y = 0; + VirtualOffset.x = 0; + VirtualOffset.y = 0; + OutTraceB("dxwSDC::GetPrimaryDC: same window\n"); + } + + if(PrimaryDC){ + if(!(*pGDIBitBlt)(VirtualHDC, 0, 0, ScreenWidth, ScreenHeight, PrimaryDC, VirtualOffset.x, VirtualOffset.y, SRCCOPY)){ + OutTraceE("dxwSDC::GetPrimaryDC: StretchBlt ERROR err=%d at=%d\n", GetLastError(), __LINE__); + _Warn("StretchBlt ERROR"); + } + OutTraceB("dxwSDC::GetPrimaryDC: fill=(0,0)-(%d,%d) from=(%d,%d)\n", ScreenWidth, ScreenHeight, VirtualOffset.x, VirtualOffset.y); + } + + POINT origin = {}; + POINT mainwin = {}; + GetDCOrgEx(hdc, &origin); + GetDCOrgEx((*pGDIGetDC)(dxw.GethWnd()), &mainwin); + origin.x -= mainwin.x; + origin.y -= mainwin.y; + OutTraceB("dxwSDC::GetPrimaryDC: origin=(%d,%d)\n", origin.x, origin.y); + + copyDcAttributes(VirtualHDC, hdc, origin); + setClippingRegion(VirtualHDC, hdc, origin); + + return VirtualHDC; +} + +/*---------------------------------------------------------------------------------+ +| | +| GetHdc: returns the DC to write for the GDI call | +| | ++---------------------------------------------------------------------------------*/ + +HDC dxwSDC::GetHdc(void) +{ + return VirtualHDC; +} + +/*---------------------------------------------------------------------------------+ +| | +| PutPrimaryDC: transfers the DC content to the primary surface and the screen | +| | ++---------------------------------------------------------------------------------*/ + +BOOL dxwSDC::PutPrimaryDC(HDC hdc, BOOL UpdateScreen, int XDest, int YDest, int nDestWidth, int nDestHeight) +{ + extern ReleaseDC_Type pReleaseDC; + extern Unlock1_Type pUnlock1; + BOOL ret; + HRESULT res; + + ret = TRUE; + if (nDestWidth == 0) nDestWidth=ScreenWidth-XDest; + if (nDestHeight == 0) nDestHeight=ScreenHeight-YDest; + + if (IsDebug){ + char sRect[81]; + if(UpdateScreen) sprintf(sRect, "pos=(%d,%d) size=(%dx%d) winoffset=(%d,%d) virtoffset=(%d,%d)", + XDest, YDest, nDestWidth, nDestHeight, WinOffset.x, WinOffset.y, VirtualOffset.x, VirtualOffset.y); + else strcpy(sRect, ""); + char *sType; + switch(VirtualSurfaceType){ + case VIRTUAL_ON_D3D: sType="D3D"; break; + case VIRTUAL_ON_DDRAW: sType="DDRAW"; break; + case VIRTUAL_ON_WINDOW: sType="WINDOW"; break; + default: sType="???"; break; + } + OutTrace("dxwSDC::PutPrimaryDC: hdc=%x type=%s update=%x %s\n", hdc, sType, UpdateScreen, sRect); + } + + if(UpdateScreen){ + switch(VirtualSurfaceType){ +#ifdef D3D9TRY + case VIRTUAL_ON_D3D: + RECT client; + SetStretchBltMode(PrimaryDC, HALFTONE); + (*pGetClientRect)(dxw.GethWnd(), &client); + if(PrimaryDC) ret=(*pGDIStretchBlt)(PrimaryDC, 0, 0, client.right, client.bottom, VirtualHDC, 0, 0, dxw.GetScreenWidth(), dxw.GetScreenHeight(), SRCCOPY); + ret=(*pGDIReleaseDC)(dxw.GethWnd(), PrimaryDC); + //ret=(*pGDIReleaseDC)(dxw.GethWnd(), PrimaryDC); + if(!ret) OutTrace("dxwSDC::PutPrimaryDC: ReleaseDC ERROR err=%d\n", GetLastError()); + //pDestSurface->Release(); + break; +#endif + case VIRTUAL_ON_DDRAW: + ret=(*pGDIBitBlt)(PrimaryDC, XDest+VirtualOffset.x, YDest+VirtualOffset.y, nDestWidth, nDestHeight, VirtualHDC, XDest, YDest, SRCCOPY); + if(!ret || (ret==GDI_ERROR)) { + OutTraceE("dxwSDC::PutPrimaryDC: BitBlt ERROR ret=%x err=%d\n", ret, GetLastError()); + } + res=(*pReleaseDC)(lpDDSPrimary, PrimaryDC); + if(res){ + OutTraceE("dxwSDC::PutPrimaryDC: ReleaseDC ERROR res=%x\n", res); + } + dxw.ScreenRefresh(); + break; + case VIRTUAL_ON_WINDOW: + SetStretchBltMode(PrimaryDC, HALFTONE); + RECT RealArea, VirtualArea; + // some fullscreen games ("Imperialism II") blitted from negative coordinates -2,-2 !! + if(XDest < 0) { + nDestWidth += XDest; + XDest=0; + } + if(YDest < 0) { + nDestHeight += YDest; + YDest=0; + } + VirtualArea.left = XDest; + VirtualArea.top = YDest; + VirtualArea.right = nDestWidth; + VirtualArea.bottom = nDestHeight; + RealArea = VirtualArea; + dxw.MapClient(&RealArea); + OffsetRect(&RealArea, WinOffset.x, WinOffset.y); + ret=TRUE; + if(PrimaryDC)ret=(*pGDIStretchBlt)(PrimaryDC, RealArea.left, RealArea.top, RealArea.right, RealArea.bottom, VirtualHDC, VirtualArea.left, VirtualArea.top, VirtualArea.right, VirtualArea.bottom, SRCCOPY); + ret=(*pGDIReleaseDC)(dxw.GethWnd(), PrimaryDC); + break; + } + } + else { + switch(VirtualSurfaceType){ + case VIRTUAL_ON_DDRAW: + res=(*pReleaseDC)(lpDDSPrimary, PrimaryDC); + if(res){ + OutTraceE("dxwSDC::PutPrimaryDC: ReleaseDC ERROR res=%x\n", res); + } + break; + case VIRTUAL_ON_WINDOW: + ret=(*pGDIReleaseDC)(dxw.GethWnd(), PrimaryDC); + if(!ret){ + OutTraceE("dxwSDC::PutPrimaryDC: ReleaseDC ERROR err=%d\n", GetLastError()); + } + break; + } + } + + OutTraceB("dxwSDC::PutPrimaryDC: hdc=%x PrimaryDC=%x ret=%x\n", hdc, PrimaryDC, ret); + return ret; +} + +BOOL dxwSDC::PutPrimaryDC(HDC hdc, BOOL UpdateScreen) +{ + return PutPrimaryDC(hdc, UpdateScreen, 0, 0, LastScreenWidth, LastScreenHeight); +} + +/*---------------------------------------------------------------------------------+ +| | +| Service routines | +| | ++---------------------------------------------------------------------------------*/ + +void dxwSDC::copyDcAttributes(HDC destDC, HDC origDc, POINT origin) +{ + origFont = SelectObject(destDC, GetCurrentObject(origDc, OBJ_FONT)); + origBrush = SelectObject(destDC, GetCurrentObject(origDc, OBJ_BRUSH)); + origPen = SelectObject(destDC, GetCurrentObject(origDc, OBJ_PEN)); + SetArcDirection(destDC, GetArcDirection(origDc)); + SetBkColor(destDC, GetBkColor(origDc)); + SetBkMode(destDC, GetBkMode(origDc)); + SetDCBrushColor(destDC, GetDCBrushColor(origDc)); + SetDCPenColor(destDC, GetDCPenColor(origDc)); + SetPolyFillMode(destDC, GetPolyFillMode(origDc)); + SetROP2(destDC, GetROP2(origDc)); + SetStretchBltMode(destDC, GetStretchBltMode(origDc)); + SetTextAlign(destDC, GetTextAlign(origDc)); + SetTextCharacterExtra(destDC, GetTextCharacterExtra(origDc)); + SetTextColor(destDC, GetTextColor(origDc)); + + OutTrace("copyDcAttributes: orig=(%d,%d)\n", origin.x, origin.y); + if(!(*pSetWindowOrgEx)(destDC, -origin.x, -origin.y, NULL)) + OutTraceE("copyDcAttributes: SetWindowOrgEx ERROR orig=(%d,%d) err=%d\n", origin.x, origin.y, GetLastError()); + + POINT brushOrg = {}; + GetBrushOrgEx(origDc, &brushOrg); + SetBrushOrgEx(destDC, brushOrg.x, brushOrg.y, NULL); + + POINT currentPos = {}; + (*pMoveToEx)(origDc, 0, 0, ¤tPos); + (*pMoveToEx)(origDc, currentPos.x, currentPos.y, NULL); + dxw.MapClient(¤tPos); + (*pMoveToEx)(destDC, currentPos.x, currentPos.y, NULL); +} + +typedef struct +{ + HDC compatDc; + POINT origin; + HWND rootWnd; +} ExcludeClipRectsData_Type; + +static BOOL CALLBACK excludeClipRectsForOverlappingWindows(HWND hwnd, LPARAM lParam) +{ + ExcludeClipRectsData_Type *excludeClipRectsData = (ExcludeClipRectsData_Type *)lParam; + if (hwnd == dxw.GethWnd()) return FALSE; // stop + if (!IsWindowVisible(hwnd)) return TRUE; // go ahead + + RECT rect = {}; + (*pGetWindowRect)(hwnd, &rect); + OffsetRect(&rect, -excludeClipRectsData->origin.x, -excludeClipRectsData->origin.y); + ExcludeClipRect(excludeClipRectsData->compatDc, rect.left, rect.top, rect.right, rect.bottom); + OutTrace("dxwSDC::excludeClipRects: hwnd=%x rect=(%d,%d)-(%d,%d)\n", hwnd, rect.left, rect.top, rect.right, rect.bottom); + return TRUE; +} + +void dxwSDC::setClippingRegion(HDC compatDc, HDC origDc, POINT& origin) +{ + OutTrace("dxwSDC::setClippingRegion: compdc=%x origdc=%x origin=(%d,%d)\n", compatDc, origDc, origin.x, origin.y); + HRGN clipRgn = CreateRectRgn(0, 0, 0, 0); + const bool isEmptyClipRgn = (1 != GetRandomRgn(origDc, clipRgn, SYSRGN)); + OutTrace("dxwSDC::setClippingRegion: isEmptyClipRgn=%x\n", isEmptyClipRgn); + // scale clip region + POINT upleft={0, 0}; + //(*pClientToScreen)(dxw.GethWnd(), &upleft); + (*pClientToScreen)(CurrenthWnd, &upleft); + if(IsDebug){ + OutTrace("dxwSDC::setClippingRegion: upleft=(%d,%d)\n", upleft.x, upleft.y); + } + OffsetRgn(clipRgn, -upleft.x, -upleft.y); + if(IsDebug){ + RECT RgnBox; + GetRgnBox(clipRgn, &RgnBox); + OutTrace("dxwSDC::setClippingRegion: RgnBox=(%d,%d)-(%d,%d) size=(%dx%d)\n", + RgnBox.left, RgnBox.top, RgnBox.right, RgnBox.bottom, RgnBox.right-RgnBox.left, RgnBox.bottom-RgnBox.top); + } + // end of scaling + SelectClipRgn(compatDc, isEmptyClipRgn ? NULL : clipRgn); + DeleteObject(clipRgn); + + HRGN origClipRgn = (*pCreateRectRgn)(0, 0, 0, 0); + if (1 == GetClipRgn(origDc, origClipRgn)) + { + OutTrace("dxwSDC::setClippingRegion: GetClipRgn==1\n"); + OffsetRgn(origClipRgn, origin.x, origin.y); + ExtSelectClipRgn(compatDc, origClipRgn, RGN_AND); + if(IsDebug){ + RECT RgnBox; + GetRgnBox(origClipRgn, &RgnBox); // for logging only + OutTrace("dxwSDC::setClippingRegion: OrigRgnBox=(%d,%d)-(%d,%d)\n", RgnBox.left, RgnBox.top, RgnBox.right, RgnBox.bottom); + } + } + DeleteObject(origClipRgn); + + return; + // to finish ..... + // on Win10 this part seems unnecessary and giving troubles ..... + //dxw.MapClient(&origin); + if (!isEmptyClipRgn) + { + HWND hwnd = WindowFromDC(origDc); + if (hwnd) + { + ExcludeClipRectsData_Type excludeClipRectsData = { compatDc, origin, GetAncestor(hwnd, GA_ROOT) }; + EnumWindows(&excludeClipRectsForOverlappingWindows,(LPARAM)(&excludeClipRectsData)); + } + } +} diff --git a/dll/shareddc.hpp b/dll/shareddc.hpp new file mode 100644 index 0000000..303ca48 --- /dev/null +++ b/dll/shareddc.hpp @@ -0,0 +1,55 @@ +#include +#include "syslibs.h" + +typedef enum { + VIRTUAL_UNDEFINED = 0, + VIRTUAL_ON_WINDOW, + VIRTUAL_ON_DDRAW, + VIRTUAL_ON_D3D, + VIRTUAL_ON_OPENGL, + VIRTUAL_ERROR +} Virtual_type; + +class dxwSDC +{ +// Construction/destruction +public: + dxwSDC(); + virtual ~dxwSDC(); + +// Operations +public: // methods + HDC GetPrimaryDC(HDC); + HDC GetHdc(void); + BOOL PutPrimaryDC(HDC, BOOL, int, int, int, int); + BOOL PutPrimaryDC(HDC, BOOL); + +private: + void copyDcAttributes(HDC, HDC, POINT); + void setClippingRegion(HDC, HDC, POINT&); + + HDC PrimaryDC; + HDC VirtualHDC; + HDC CurrentHDC; + HWND CurrenthWnd; + LPDIRECTDRAWSURFACE lpDDSPrimary; + HBITMAP VirtualPic; + HGDIOBJ origFont; + HGDIOBJ origBrush; + HGDIOBJ origPen; + POINT WinOffset; + POINT VirtualOffset; + int ScreenWidth, ScreenHeight; + int LastScreenWidth, LastScreenHeight; + HDC LastHDC; + Virtual_type VirtualSurfaceType; + struct ExcludeClipRectsData + { + HDC compatDc; + POINT origin; + HWND rootWnd; + }; + +}; + +extern dxwSDC sdc; \ No newline at end of file diff --git a/dll/syslibs.h b/dll/syslibs.h index efd5d5b..3051c58 100644 --- a/dll/syslibs.h +++ b/dll/syslibs.h @@ -38,7 +38,8 @@ typedef BOOL (WINAPI *ImmGetOpenStatus_Type)(HIMC); // GDI32.dll: typedef BOOL (WINAPI *BitBlt_Type)(HDC, int, int, int, int, HDC, int, int, DWORD); typedef HDC (WINAPI *CreateCompatibleDC_Type)(HDC); -typedef HDC (WINAPI *CreateDC_Type)(LPCSTR, LPCSTR, LPCSTR, const DEVMODE *); +typedef HDC (WINAPI *CreateDCA_Type)(LPCSTR, LPCSTR, LPCSTR, const DEVMODE *); +typedef HDC (WINAPI *CreateDCW_Type)(LPWSTR, LPWSTR, LPWSTR, const DEVMODE *); typedef HFONT (WINAPI *CreateFont_Type)(int, int, int, int, int, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, LPCTSTR); typedef HFONT (WINAPI *CreateFontIndirect_Type)(const LOGFONT*); typedef HDC (WINAPI *CreateICA_Type)(LPCTSTR, LPCTSTR, LPCTSTR, const DEVMODE *); @@ -69,7 +70,9 @@ typedef BOOL (WINAPI *SetDeviceGammaRamp_Type)(HDC, LPVOID); typedef COLORREF(WINAPI *SetTextColor_Type)(HDC, COLORREF); typedef BOOL (WINAPI *StretchBlt_Type)(HDC, int, int, int, int, HDC, int, int, int, int, DWORD); typedef int (WINAPI *StretchDIBits_Type)(HDC, int, int, int, int, int, int, int, int, const VOID *, const BITMAPINFO *, UINT, DWORD); -typedef BOOL (WINAPI *TextOut_Type)(HDC, int, int, LPCTSTR, int); +typedef BOOL (WINAPI *TextOutA_Type)(HDC, int, int, LPCTSTR, int); +typedef BOOL (WINAPI *TextOutW_Type)(HDC, int, int, LPCWSTR, int); +typedef BOOL (WINAPI *PolyBezier_Type)(HDC, const POINT *, DWORD); typedef BOOL (WINAPI *PolyBezierTo_Type)(HDC, const POINT *, DWORD); typedef BOOL (WINAPI *PolylineTo_Type)(HDC, const POINT *, DWORD); typedef BOOL (WINAPI *PolyDraw_Type)(HDC, const POINT *, const BYTE *, int); @@ -161,8 +164,10 @@ typedef HWND (WINAPI *CreateDialogParam_Type)(HINSTANCE, LPCTSTR, HWND, DLGPROC, typedef HWND (WINAPI *CreateWindowExA_Type)(DWORD, LPCTSTR, LPCTSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, LPVOID); typedef HWND (WINAPI *CreateWindowExW_Type)(DWORD, LPCWSTR, LPCWSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, LPVOID); typedef LRESULT (WINAPI *DefWindowProc_Type)(HWND, UINT, WPARAM, LPARAM); -typedef int (WINAPI *DrawText_Type)(HDC, LPCTSTR, int, LPRECT, UINT); -typedef int (WINAPI *DrawTextEx_Type)(HDC, LPTSTR, int, LPRECT, UINT, LPDRAWTEXTPARAMS); +typedef int (WINAPI *DrawTextA_Type)(HDC, LPCTSTR, int, LPRECT, UINT); +typedef int (WINAPI *DrawTextW_Type)(HDC, LPCWSTR, int, LPRECT, UINT); +typedef int (WINAPI *DrawTextExA_Type)(HDC, LPCTSTR, int, LPRECT, UINT, LPDRAWTEXTPARAMS); +typedef int (WINAPI *DrawTextExW_Type)(HDC, LPCWSTR, int, LPRECT, UINT, LPDRAWTEXTPARAMS); typedef BOOL (WINAPI *EndPaint_Type)(HWND, const PAINTSTRUCT *); typedef LONG (WINAPI *EnumDisplaySettings_Type)(LPCTSTR, DWORD, LPDEVMODEA); typedef int (WINAPI *FillRect_Type)(HDC, const RECT *, HBRUSH); @@ -184,8 +189,10 @@ typedef int (WINAPI *MapWindowPoints_Type)(HWND, HWND, LPPOINT, UINT); typedef BOOL (WINAPI *MoveWindow_Type)(HWND, int, int, int, int, BOOL); typedef BOOL (WINAPI *PeekMessage_Type)(LPMSG, HWND, UINT, UINT, UINT); typedef BOOL (WINAPI *RedrawWindow_Type)(HWND, const RECT *, HRGN, UINT); -typedef ATOM (WINAPI *RegisterClassExA_Type)(WNDCLASSEX *); -typedef ATOM (WINAPI *RegisterClassA_Type)(WNDCLASS *); +typedef ATOM (WINAPI *RegisterClassExA_Type)(WNDCLASSEXA *); +typedef ATOM (WINAPI *RegisterClassA_Type)(WNDCLASSA *); +typedef ATOM (WINAPI *RegisterClassExW_Type)(WNDCLASSEXW *); +typedef ATOM (WINAPI *RegisterClassW_Type)(WNDCLASSW *); typedef int (WINAPI *GDIReleaseDC_Type)(HWND, HDC); typedef BOOL (WINAPI *ScreenToClient_Type)(HWND, LPPOINT); typedef LRESULT (WINAPI *SendMessage_Type)(HWND, UINT, WPARAM, LPARAM); @@ -197,6 +204,7 @@ typedef BOOL (WINAPI *SetWindowPos_Type)(HWND, HWND, int, int, int, int, UINT); typedef int (WINAPI *ShowCursor_Type)(BOOL); typedef BOOL (WINAPI *ShowWindow_Type)(HWND, int); typedef LONG (WINAPI *TabbedTextOutA_Type)(HDC, int, int, LPCTSTR, int, int, const LPINT, int); +typedef LONG (WINAPI *TabbedTextOutW_Type)(HDC, int, int, LPCWSTR, int, int, const LPINT, int); typedef BOOL (WINAPI *DestroyWindow_Type)(HWND); typedef BOOL (WINAPI *CloseWindow_Type)(HWND); typedef BOOL (WINAPI *SetSysColors_Type)(int, const INT *, const COLORREF *); @@ -264,7 +272,8 @@ DXWEXTERN ImmGetOpenStatus_Type pImmGetOpenStatus DXWINITIALIZED; // GDI32.dll: DXWEXTERN BitBlt_Type pGDIBitBlt DXWINITIALIZED; DXWEXTERN CreateCompatibleDC_Type pGDICreateCompatibleDC DXWINITIALIZED; -DXWEXTERN CreateDC_Type pGDICreateDC DXWINITIALIZED; +DXWEXTERN CreateDCA_Type pGDICreateDCA DXWINITIALIZED; +DXWEXTERN CreateDCW_Type pGDICreateDCW DXWINITIALIZED; DXWEXTERN CreateFont_Type pGDICreateFont DXWINITIALIZED; DXWEXTERN CreateFontIndirect_Type pGDICreateFontIndirect DXWINITIALIZED; DXWEXTERN CreateICA_Type pCreateICA DXWINITIALIZED; @@ -295,12 +304,14 @@ DXWEXTERN SetDeviceGammaRamp_Type pGDISetDeviceGammaRamp DXWINITIALIZED; DXWEXTERN SetTextColor_Type pGDISetTextColor DXWINITIALIZED; DXWEXTERN StretchBlt_Type pGDIStretchBlt DXWINITIALIZED; DXWEXTERN StretchDIBits_Type pStretchDIBits DXWINITIALIZED; -DXWEXTERN TextOut_Type pGDITextOutA DXWINITIALIZED; +DXWEXTERN TextOutA_Type pGDITextOutA DXWINITIALIZED; +DXWEXTERN TextOutW_Type pGDITextOutW DXWINITIALIZED; DXWEXTERN LineTo_Type pLineTo DXWINITIALIZED; DXWEXTERN ArcTo_Type pArcTo DXWINITIALIZED; DXWEXTERN MoveToEx_Type pMoveToEx DXWINITIALIZED; DXWEXTERN PolyDraw_Type pPolyDraw DXWINITIALIZED; DXWEXTERN PolylineTo_Type pPolylineTo DXWINITIALIZED; +DXWEXTERN PolyBezier_Type pPolyBezier DXWINITIALIZED; DXWEXTERN PolyBezierTo_Type pPolyBezierTo DXWINITIALIZED; DXWEXTERN SetDIBitsToDevice_Type pSetDIBitsToDevice DXWINITIALIZED; DXWEXTERN CreateCompatibleBitmap_Type pCreateCompatibleBitmap DXWINITIALIZED; @@ -387,8 +398,10 @@ DXWEXTERN CreateWindowExA_Type pCreateWindowExA DXWINITIALIZED; DXWEXTERN CreateWindowExW_Type pCreateWindowExW DXWINITIALIZED; DXWEXTERN DefWindowProc_Type pDefWindowProcA DXWINITIALIZED; DXWEXTERN DefWindowProc_Type pDefWindowProcW DXWINITIALIZED; -DXWEXTERN DrawText_Type pDrawText DXWINITIALIZED; -DXWEXTERN DrawTextEx_Type pDrawTextEx DXWINITIALIZED; +DXWEXTERN DrawTextA_Type pDrawTextA DXWINITIALIZED; +DXWEXTERN DrawTextW_Type pDrawTextW DXWINITIALIZED; +DXWEXTERN DrawTextExA_Type pDrawTextExA DXWINITIALIZED; +DXWEXTERN DrawTextExW_Type pDrawTextExW DXWINITIALIZED; DXWEXTERN EndPaint_Type pEndPaint DXWINITIALIZED; DXWEXTERN EnumDisplaySettings_Type pEnumDisplaySettings DXWINITIALIZED; DXWEXTERN FillRect_Type pFillRect DXWINITIALIZED; @@ -414,6 +427,8 @@ DXWEXTERN PeekMessage_Type pPeekMessage DXWINITIALIZED; DXWEXTERN RedrawWindow_Type pRedrawWindow DXWINITIALIZED; DXWEXTERN RegisterClassExA_Type pRegisterClassExA DXWINITIALIZED; DXWEXTERN RegisterClassA_Type pRegisterClassA DXWINITIALIZED; +DXWEXTERN RegisterClassExW_Type pRegisterClassExW DXWINITIALIZED; +DXWEXTERN RegisterClassW_Type pRegisterClassW DXWINITIALIZED; DXWEXTERN GDIReleaseDC_Type pGDIReleaseDC DXWINITIALIZED; DXWEXTERN ScreenToClient_Type pScreenToClient DXWINITIALIZED; DXWEXTERN SendMessage_Type pSendMessageA DXWINITIALIZED; @@ -427,6 +442,7 @@ DXWEXTERN SetWindowPos_Type pSetWindowPos DXWINITIALIZED; DXWEXTERN ShowCursor_Type pShowCursor DXWINITIALIZED; DXWEXTERN ShowWindow_Type pShowWindow DXWINITIALIZED; DXWEXTERN TabbedTextOutA_Type pTabbedTextOutA DXWINITIALIZED; +DXWEXTERN TabbedTextOutW_Type pTabbedTextOutW DXWINITIALIZED; DXWEXTERN DestroyWindow_Type pDestroyWindow DXWINITIALIZED; DXWEXTERN CloseWindow_Type pCloseWindow DXWINITIALIZED; DXWEXTERN SetSysColors_Type pSetSysColors DXWINITIALIZED; @@ -485,7 +501,8 @@ extern BOOL WINAPI extImmGetOpenStatus(HIMC); extern BOOL WINAPI extGDIBitBlt(HDC, int, int, int, int, HDC, int, int, DWORD); extern HDC WINAPI extGDICreateCompatibleDC(HDC); extern HDC WINAPI extEMUCreateCompatibleDC(HDC); -extern HDC WINAPI extGDICreateDC(LPSTR, LPSTR, LPSTR, CONST DEVMODE *); +extern HDC WINAPI extGDICreateDCA(LPSTR, LPSTR, LPSTR, CONST DEVMODE *); +extern HDC WINAPI extGDICreateDCW(LPWSTR, LPWSTR, LPWSTR, CONST DEVMODE *); extern HFONT WINAPI extCreateFont(int, int, int, int, int, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, LPCTSTR); extern HFONT WINAPI extCreateFontIndirect(const LOGFONT*); extern HDC WINAPI extCreateICA(LPCTSTR, LPCTSTR, LPCTSTR, const DEVMODE *); @@ -515,6 +532,8 @@ extern BOOL WINAPI extSetDeviceGammaRamp(HDC, LPVOID); extern BOOL WINAPI extGDIStretchBlt(HDC, int, int, int, int, HDC, int, int, int, int, DWORD); extern int WINAPI extStretchDIBits(HDC, int, int, int, int, int, int, int, int, const VOID *, const BITMAPINFO *, UINT, DWORD); extern BOOL WINAPI extTextOutA(HDC, int, int, LPCTSTR, int); +extern BOOL WINAPI extTextOutW(HDC, int, int, LPCWSTR, int); +extern BOOL WINAPI extPolyBezier(HDC, const POINT *, DWORD); extern BOOL WINAPI extPolyBezierTo(HDC, const POINT *, DWORD); extern BOOL WINAPI extPolylineTo(HDC, const POINT *, DWORD); extern BOOL WINAPI extPolyDraw(HDC, const POINT *, const BYTE *, int); @@ -610,6 +629,8 @@ extern LRESULT WINAPI extDefWindowProcA(HWND, UINT, WPARAM, LPARAM); extern LRESULT WINAPI extDefWindowProcW(HWND, UINT, WPARAM, LPARAM); extern int WINAPI extDrawTextA(HDC, LPCTSTR, int, LPRECT, UINT); extern int WINAPI extDrawTextExA(HDC, LPTSTR, int, LPRECT, UINT, LPDRAWTEXTPARAMS); +extern int WINAPI extDrawTextW(HDC, LPCWSTR, int, LPRECT, UINT); +extern int WINAPI extDrawTextExW(HDC, LPCWSTR, int, LPRECT, UINT, LPDRAWTEXTPARAMS); extern BOOL WINAPI extEndPaint(HWND, const PAINTSTRUCT *); extern LONG WINAPI extEnumDisplaySettings(LPCTSTR, DWORD, DEVMODE *); extern int WINAPI extFillRect(HDC, const RECT *, HBRUSH); @@ -618,7 +639,6 @@ extern BOOL WINAPI extGetClientRect(HWND, LPRECT); extern BOOL WINAPI extGetClipCursor(LPRECT); extern BOOL WINAPI extGetCursorPos(LPPOINT); extern HDC WINAPI extGDIGetDC(HWND); -extern HDC WINAPI extEMUGetDC(HWND); extern HWND WINAPI extGetDesktopWindow(void); extern BOOL WINAPI extGetMonitorInfoA(HMONITOR, LPMONITORINFO); extern BOOL WINAPI extGetMonitorInfoW(HMONITOR, LPMONITORINFO); @@ -636,6 +656,8 @@ extern BOOL WINAPI extPeekMessage(LPMSG, HWND, UINT, UINT, UINT); extern BOOL WINAPI extRedrawWindow(HWND, const RECT *, HRGN, UINT); extern ATOM WINAPI extRegisterClassExA(WNDCLASSEXA *); extern ATOM WINAPI extRegisterClassA(WNDCLASSA *); +extern ATOM WINAPI extRegisterClassExW(WNDCLASSEXW *); +extern ATOM WINAPI extRegisterClassW(WNDCLASSW *); extern int WINAPI extGDIReleaseDC(HWND, HDC); extern BOOL WINAPI extScreenToClient(HWND, LPPOINT); extern LRESULT WINAPI extSendMessageA(HWND, UINT, WPARAM, LPARAM); @@ -649,6 +671,7 @@ extern BOOL WINAPI extSetWindowPos(HWND, HWND, int, int, int, int, UINT); extern int WINAPI extShowCursor(BOOL); extern BOOL WINAPI extShowWindow(HWND, int); extern LONG WINAPI extTabbedTextOutA(HDC, int, int, LPCTSTR, int, int, const LPINT, int); +extern LONG WINAPI extTabbedTextOutW(HDC, int, int, LPCWSTR, int, int, const LPINT, int); extern BOOL WINAPI extDestroyWindow(HWND); extern BOOL WINAPI extCloseWindow(HWND); extern BOOL WINAPI extSetSysColors(int, const INT *, const COLORREF *); @@ -687,3 +710,4 @@ extern void HookGDI32Init(); extern void HookImagehlpInit(); /* eof */ + diff --git a/dll/user32.09.cpp b/dll/user32.09.cpp new file mode 100644 index 0000000..61dc1fe --- /dev/null +++ b/dll/user32.09.cpp @@ -0,0 +1,3302 @@ +#define _WIN32_WINNT 0x0600 +#define WIN32_LEAN_AND_MEAN +#define _CRT_SECURE_NO_WARNINGS +#define _CRT_NON_CONFORMING_SWPRINTFS + +#include +#include +#include "dxwnd.h" +#include "dxwcore.hpp" +#include "syslibs.h" +#include "dxhook.h" +#include "hddraw.h" +#include "dxhelper.h" +#include "shareddc.hpp" + +#define FIXCHILDSIZE FALSE + +BOOL IsChangeDisplaySettingsHotPatched = FALSE; +extern BOOL bFlippedDC; +extern HDC hFlippedDC; + +//typedef BOOL (WINAPI *EnumDisplayMonitors_Type)(HDC, LPCRECT, MONITORENUMPROC, LPARAM); +//EnumDisplayMonitors_Type pEnumDisplayMonitors = NULL; +//BOOL WINAPI extEnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM); + +typedef BOOL (WINAPI *BringWindowToTop_Type)(HWND); +BringWindowToTop_Type pBringWindowToTop = NULL; +BOOL WINAPI extBringWindowToTop(HWND); +typedef BOOL (WINAPI *SetForegroundWindow_Type)(HWND); +SetForegroundWindow_Type pSetForegroundWindow = NULL; +BOOL WINAPI extSetForegroundWindow(HWND); +typedef HHOOK (WINAPI *SetWindowsHookEx_Type)(int, HOOKPROC, HINSTANCE, DWORD); +SetWindowsHookEx_Type pSetWindowsHookEx = NULL; +HHOOK WINAPI extSetWindowsHookEx(int, HOOKPROC, HINSTANCE, DWORD); +typedef BOOL (WINAPI *PostMessageA_Type)(HWND, UINT, WPARAM, LPARAM); +PostMessageA_Type pPostMessageA = NULL; +BOOL WINAPI extPostMessageA(HWND, UINT, WPARAM, LPARAM); +typedef HRESULT (WINAPI *MessageBoxTimeoutA_Type)(HWND, LPCSTR, LPCSTR, UINT, WORD, DWORD); +MessageBoxTimeoutA_Type pMessageBoxTimeoutA = NULL; +HRESULT WINAPI extMessageBoxTimeoutA(HWND, LPCSTR, LPCSTR, UINT, WORD, DWORD); +typedef HRESULT (WINAPI *MessageBoxTimeoutW_Type)(HWND, LPCWSTR, LPCWSTR, UINT, WORD, DWORD); +MessageBoxTimeoutW_Type pMessageBoxTimeoutW = NULL; +HRESULT WINAPI extMessageBoxTimeoutW(HWND, LPCWSTR, LPCWSTR, UINT, WORD, DWORD); +typedef BOOL (WINAPI *IsIconic_Type)(HWND); +IsIconic_Type pIsIconic = NULL; +BOOL WINAPI extIsIconic(HWND); +typedef BOOL (WINAPI *IsZoomed_Type)(HWND); +IsZoomed_Type pIsZoomed = NULL; +BOOL WINAPI extIsZoomed(HWND); +typedef HDESK (WINAPI *CreateDesktop_Type)(LPCTSTR, LPCTSTR, DEVMODE *, DWORD, ACCESS_MASK, LPSECURITY_ATTRIBUTES); +CreateDesktop_Type pCreateDesktop = NULL; +HDESK WINAPI extCreateDesktop(LPCTSTR, LPCTSTR, DEVMODE *, DWORD, ACCESS_MASK, LPSECURITY_ATTRIBUTES); +typedef BOOL (WINAPI *SwitchDesktop_Type)(HDESK); +SwitchDesktop_Type pSwitchDesktop = NULL; +BOOL WINAPI extSwitchDesktop(HDESK); +typedef HDESK (WINAPI *OpenDesktop_Type)(LPTSTR, DWORD, BOOL, ACCESS_MASK); +OpenDesktop_Type pOpenDesktop = NULL; +HDESK WINAPI extOpenDesktop(LPTSTR, DWORD, BOOL, ACCESS_MASK); +typedef BOOL (WINAPI *CloseDesktop_Type)(HDESK); +CloseDesktop_Type pCloseDesktop = NULL; +BOOL WINAPI extCloseDesktop(HDESK); +typedef int (WINAPI *ValidateRect_Type)(HWND, const RECT *); +ValidateRect_Type pValidateRect = NULL; +int WINAPI extValidateRect(HWND, const RECT *); +typedef BOOL (WINAPI *ScrollWindow_Type)(HWND, int, int, const RECT *, const RECT *); +ScrollWindow_Type pScrollWindow = NULL; +BOOL extScrollWindow(HWND, int, int, const RECT *, const RECT *); +typedef INT_PTR (WINAPI *DialogBoxParamA_Type)(HINSTANCE, LPCTSTR, HWND, DLGPROC, LPARAM); +DialogBoxParamA_Type pDialogBoxParamA = NULL; +INT_PTR WINAPI extDialogBoxParamA(HINSTANCE, LPCTSTR, HWND, DLGPROC, LPARAM); +typedef HWND (WINAPI *GetParent_Type)(HWND); +GetParent_Type pGetParent = NULL; +HWND WINAPI extGetParent(HWND); +typedef BOOL (WINAPI *InvalidateRgn_Type)(HWND, HRGN, BOOL); +InvalidateRgn_Type pInvalidateRgn = NULL; +BOOL WINAPI extInvalidateRgn(HWND, HRGN, BOOL); +typedef BOOL (WINAPI *InvertRect_Type)(HDC, const RECT *); +InvertRect_Type pInvertRect = NULL; +BOOL WINAPI extInvertRect(HDC, const RECT *); +typedef BOOL (WINAPI *ScrollDC_Type)(HDC, int, int, const RECT *, const RECT *, HRGN, LPRECT); +ScrollDC_Type pScrollDC = NULL; +BOOL WINAPI extScrollDC(HDC, int, int, const RECT *, const RECT *, HRGN, LPRECT); + +#ifdef TRACEPALETTE +typedef UINT (WINAPI *GetDIBColorTable_Type)(HDC, UINT, UINT, RGBQUAD *); +GetDIBColorTable_Type pGetDIBColorTable = NULL; +UINT WINAPI extGetDIBColorTable(HDC, UINT, UINT, RGBQUAD *); +typedef UINT (WINAPI *SetDIBColorTable_Type)(HDC, UINT, UINT, const RGBQUAD *); +SetDIBColorTable_Type pSetDIBColorTable = NULL; +UINT WINAPI extSetDIBColorTable(HDC, UINT, UINT, const RGBQUAD *); +#endif + +static HookEntry_Type Hooks[]={ + {HOOK_IAT_CANDIDATE, "UpdateWindow", (FARPROC)NULL, (FARPROC *)&pUpdateWindow, (FARPROC)extUpdateWindow}, + //{HOOK_IAT_CANDIDATE, "GetWindowPlacement", (FARPROC)NULL, (FARPROC *)&pGetWindowPlacement, (FARPROC)extGetWindowPlacement}, + //{HOOK_IAT_CANDIDATE, "SetWindowPlacement", (FARPROC)NULL, (FARPROC *)&pSetWindowPlacement, (FARPROC)extSetWindowPlacement}, + {HOOK_HOT_CANDIDATE, "ChangeDisplaySettingsA", (FARPROC)ChangeDisplaySettingsA, (FARPROC *)&pChangeDisplaySettingsA, (FARPROC)extChangeDisplaySettingsA}, + {HOOK_HOT_CANDIDATE, "ChangeDisplaySettingsExA", (FARPROC)ChangeDisplaySettingsExA, (FARPROC *)&pChangeDisplaySettingsExA, (FARPROC)extChangeDisplaySettingsExA}, + {HOOK_HOT_CANDIDATE, "ChangeDisplaySettingsW", (FARPROC)NULL, (FARPROC *)&pChangeDisplaySettingsW, (FARPROC)extChangeDisplaySettingsW}, // ref. by Knights of Honor + {HOOK_HOT_CANDIDATE, "ChangeDisplaySettingsExW", (FARPROC)NULL, (FARPROC *)&pChangeDisplaySettingsExW, (FARPROC)extChangeDisplaySettingsExW}, + {HOOK_HOT_CANDIDATE, "GetMonitorInfoA", (FARPROC)GetMonitorInfoA, (FARPROC *)&pGetMonitorInfoA, (FARPROC)extGetMonitorInfoA}, + {HOOK_HOT_CANDIDATE, "GetMonitorInfoW", (FARPROC)GetMonitorInfoW, (FARPROC *)&pGetMonitorInfoW, (FARPROC)extGetMonitorInfoW}, + {HOOK_HOT_CANDIDATE, "ShowCursor", (FARPROC)ShowCursor, (FARPROC *)&pShowCursor, (FARPROC)extShowCursor}, + {HOOK_IAT_CANDIDATE, "CreateDialogIndirectParamA", (FARPROC)CreateDialogIndirectParamA, (FARPROC *)&pCreateDialogIndirectParam, (FARPROC)extCreateDialogIndirectParam}, + {HOOK_IAT_CANDIDATE, "CreateDialogParamA", (FARPROC)CreateDialogParamA, (FARPROC *)&pCreateDialogParam, (FARPROC)extCreateDialogParam}, + {HOOK_IAT_CANDIDATE, "MoveWindow", (FARPROC)MoveWindow, (FARPROC *)&pMoveWindow, (FARPROC)extMoveWindow}, + {HOOK_HOT_CANDIDATE, "EnumDisplaySettingsA", (FARPROC)EnumDisplaySettingsA, (FARPROC *)&pEnumDisplaySettings, (FARPROC)extEnumDisplaySettings}, + {HOOK_IAT_CANDIDATE, "GetClipCursor", (FARPROC)GetClipCursor, (FARPROC*)&pGetClipCursor, (FARPROC)extGetClipCursor}, + {HOOK_IAT_CANDIDATE, "ClipCursor", (FARPROC)ClipCursor, (FARPROC *)&pClipCursor, (FARPROC)extClipCursor}, + {HOOK_IAT_CANDIDATE, "DefWindowProcA", (FARPROC)DefWindowProcA, (FARPROC *)&pDefWindowProcA, (FARPROC)extDefWindowProcA}, + {HOOK_IAT_CANDIDATE, "DefWindowProcW", (FARPROC)DefWindowProcW, (FARPROC *)&pDefWindowProcW, (FARPROC)extDefWindowProcW}, + {HOOK_HOT_CANDIDATE, "CreateWindowExA", (FARPROC)CreateWindowExA, (FARPROC *)&pCreateWindowExA, (FARPROC)extCreateWindowExA}, + {HOOK_HOT_CANDIDATE, "CreateWindowExW", (FARPROC)CreateWindowExW, (FARPROC *)&pCreateWindowExW, (FARPROC)extCreateWindowExW}, + {HOOK_IAT_CANDIDATE, "RegisterClassExA", (FARPROC)RegisterClassExA, (FARPROC *)&pRegisterClassExA, (FARPROC)extRegisterClassExA}, + {HOOK_IAT_CANDIDATE, "RegisterClassA", (FARPROC)RegisterClassA, (FARPROC *)&pRegisterClassA, (FARPROC)extRegisterClassA}, + {HOOK_HOT_CANDIDATE, "GetSystemMetrics", (FARPROC)GetSystemMetrics, (FARPROC *)&pGetSystemMetrics, (FARPROC)extGetSystemMetrics}, + {HOOK_HOT_CANDIDATE, "GetDesktopWindow", (FARPROC)GetDesktopWindow, (FARPROC *)&pGetDesktopWindow, (FARPROC)extGetDesktopWindow}, + {HOOK_IAT_CANDIDATE, "CloseWindow", (FARPROC)NULL, (FARPROC *)&pCloseWindow, (FARPROC)extCloseWindow}, + {HOOK_IAT_CANDIDATE, "DestroyWindow", (FARPROC)NULL, (FARPROC *)&pDestroyWindow, (FARPROC)extDestroyWindow}, + {HOOK_IAT_CANDIDATE, "SetSysColors", (FARPROC)NULL, (FARPROC *)&pSetSysColors, (FARPROC)extSetSysColors}, + {HOOK_IAT_CANDIDATE, "SetCapture", (FARPROC)NULL, (FARPROC *)&pSetCapture, (FARPROC)extSetCapture}, + {HOOK_HOT_CANDIDATE, "SetWindowLongA", (FARPROC)SetWindowLongA, (FARPROC *)&pSetWindowLongA, (FARPROC)extSetWindowLongA}, + {HOOK_HOT_CANDIDATE, "GetWindowLongA", (FARPROC)GetWindowLongA, (FARPROC *)&pGetWindowLongA, (FARPROC)extGetWindowLongA}, + {HOOK_HOT_CANDIDATE, "SetWindowLongW", (FARPROC)SetWindowLongW, (FARPROC *)&pSetWindowLongW, (FARPROC)extSetWindowLongW}, + {HOOK_HOT_CANDIDATE, "GetWindowLongW", (FARPROC)GetWindowLongW, (FARPROC *)&pGetWindowLongW, (FARPROC)extGetWindowLongW}, + {HOOK_IAT_CANDIDATE, "IsWindowVisible", (FARPROC)NULL, (FARPROC *)&pIsWindowVisible, (FARPROC)extIsWindowVisible}, + // hot by MinHook since v2.03.07 + {HOOK_HOT_CANDIDATE, "SystemParametersInfoA", (FARPROC)SystemParametersInfoA, (FARPROC *)&pSystemParametersInfoA, (FARPROC)extSystemParametersInfoA}, + {HOOK_HOT_CANDIDATE, "SystemParametersInfoW", (FARPROC)SystemParametersInfoW, (FARPROC *)&pSystemParametersInfoW, (FARPROC)extSystemParametersInfoW}, + //{HOOK_HOT_CANDIDATE, "GetActiveWindow", (FARPROC)NULL, (FARPROC *)&pGetActiveWindow, (FARPROC)extGetActiveWindow}, + //{HOOK_HOT_CANDIDATE, "GetForegroundWindow", (FARPROC)GetForegroundWindow, (FARPROC *)&pGetForegroundWindow, (FARPROC)extGetForegroundWindow}, + //{HOOK_IAT_CANDIDATE, "GetWindowTextA", (FARPROC)GetWindowTextA, (FARPROC *)&pGetWindowTextA, (FARPROC)extGetWindowTextA}, + //{HOOK_HOT_CANDIDATE, "EnumDisplayMonitors", (FARPROC)EnumDisplayMonitors, (FARPROC *)&pEnumDisplayMonitors, (FARPROC)extEnumDisplayMonitors}, +#ifdef TRACEPALETTE + {HOOK_HOT_CANDIDATE, "GetDIBColorTable", (FARPROC)GetDIBColorTable, (FARPROC *)&pGetDIBColorTable, (FARPROC)extGetDIBColorTable}, + {HOOK_HOT_CANDIDATE, "SetDIBColorTable", (FARPROC)SetDIBColorTable, (FARPROC *)&pSetDIBColorTable, (FARPROC)extSetDIBColorTable}, +#endif + + {HOOK_HOT_CANDIDATE, "BringWindowToTop", (FARPROC)BringWindowToTop, (FARPROC *)&pBringWindowToTop, (FARPROC)extBringWindowToTop}, + {HOOK_HOT_CANDIDATE, "SetForegroundWindow", (FARPROC)SetForegroundWindow, (FARPROC *)&pSetForegroundWindow, (FARPROC)extSetForegroundWindow}, + {HOOK_HOT_CANDIDATE, "ChildWindowFromPoint", (FARPROC)ChildWindowFromPoint, (FARPROC *)&pChildWindowFromPoint, (FARPROC)extChildWindowFromPoint}, + {HOOK_HOT_CANDIDATE, "ChildWindowFromPointEx", (FARPROC)ChildWindowFromPointEx, (FARPROC *)&pChildWindowFromPointEx, (FARPROC)extChildWindowFromPointEx}, + {HOOK_HOT_CANDIDATE, "WindowFromPoint", (FARPROC)WindowFromPoint, (FARPROC *)&pWindowFromPoint, (FARPROC)extWindowFromPoint}, + {HOOK_HOT_CANDIDATE, "SetWindowsHookExA", (FARPROC)SetWindowsHookExA, (FARPROC *)&pSetWindowsHookEx, (FARPROC)extSetWindowsHookEx}, + + //{HOOK_HOT_CANDIDATE, "MessageBoxTimeoutA", (FARPROC)NULL, (FARPROC *)&pMessageBoxTimeoutA, (FARPROC)extMessageBoxTimeoutA}, + //{HOOK_HOT_CANDIDATE, "MessageBoxTimeoutW", (FARPROC)NULL, (FARPROC *)&pMessageBoxTimeoutW, (FARPROC)extMessageBoxTimeoutW}, + + {HOOK_IAT_CANDIDATE, "GetDC", (FARPROC)GetDC, (FARPROC *)&pGDIGetDC, (FARPROC)extGDIGetDC}, + {HOOK_IAT_CANDIDATE, "GetDCEx", (FARPROC)GetDCEx, (FARPROC *)&pGDIGetDCEx, (FARPROC)extGDIGetDCEx}, + {HOOK_IAT_CANDIDATE, "GetWindowDC", (FARPROC)GetWindowDC, (FARPROC *)&pGDIGetWindowDC, (FARPROC)extGDIGetWindowDC}, + {HOOK_IAT_CANDIDATE, "ReleaseDC", (FARPROC)ReleaseDC, (FARPROC *)&pGDIReleaseDC, (FARPROC)extGDIReleaseDC}, + + {HOOK_HOT_CANDIDATE, "BeginPaint", (FARPROC)BeginPaint, (FARPROC *)&pBeginPaint, (FARPROC)extBeginPaint}, + {HOOK_HOT_CANDIDATE, "EndPaint", (FARPROC)EndPaint, (FARPROC *)&pEndPaint, (FARPROC)extEndPaint}, + + {HOOK_IAT_CANDIDATE, "DialogBoxParamA", (FARPROC)NULL, (FARPROC *)&pDialogBoxParamA, (FARPROC)extDialogBoxParamA}, + + //{HOOK_IAT_CANDIDATE, "IsZoomed", (FARPROC)NULL, (FARPROC *)&pIsZoomed, (FARPROC)extIsZoomed}, + //{HOOK_HOT_CANDIDATE, "IsIconic", (FARPROC)IsIconic, (FARPROC *)&pIsIconic, (FARPROC)extIsIconic}, + + {HOOK_HOT_CANDIDATE, "FillRect", (FARPROC)FillRect, (FARPROC *)&pFillRect, (FARPROC)extFillRect}, + {HOOK_IAT_CANDIDATE, "FrameRect", (FARPROC)FrameRect, (FARPROC *)&pFrameRect, (FARPROC)extFrameRect}, + {HOOK_IAT_CANDIDATE, "RedrawWindow", (FARPROC)RedrawWindow, (FARPROC *)&pRedrawWindow, (FARPROC)extRedrawWindow}, + {HOOK_HOT_CANDIDATE, "GetParent", (FARPROC)GetParent, (FARPROC *)&pGetParent, (FARPROC)extGetParent}, + {HOOK_HOT_CANDIDATE, "InvalidateRgn", (FARPROC)InvalidateRgn, (FARPROC *)&pInvalidateRgn, (FARPROC)extInvalidateRgn}, + {HOOK_IAT_CANDIDATE, "TabbedTextOutA", (FARPROC)TabbedTextOutA, (FARPROC *)&pTabbedTextOutA, (FARPROC)extTabbedTextOutA}, + {HOOK_IAT_CANDIDATE, "ScrollDC", (FARPROC)ScrollDC, (FARPROC *)&pScrollDC, (FARPROC)extScrollDC}, + {HOOK_IAT_CANDIDATE, "InvalidateRect", (FARPROC)InvalidateRect, (FARPROC *)&pInvalidateRect, (FARPROC)extInvalidateRect}, + {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator +}; + +static HookEntry_Type NoGDIHooks[]={ + {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator +}; + +static HookEntry_Type EmulateHooks[]={ + //{HOOK_IAT_CANDIDATE, "GetDC", (FARPROC)GetDC, (FARPROC *)&pGDIGetDC, (FARPROC)extGDIGetDC}, + //{HOOK_IAT_CANDIDATE, "GetDCEx", (FARPROC)GetDCEx, (FARPROC *)&pGDIGetDCEx, (FARPROC)extGDIGetDCEx}, + //{HOOK_IAT_CANDIDATE, "GetWindowDC", (FARPROC)GetWindowDC, (FARPROC *)&pGDIGetWindowDC, (FARPROC)extGDIGetWindowDC}, + //{HOOK_IAT_CANDIDATE, "ReleaseDC", (FARPROC)ReleaseDC, (FARPROC *)&pGDIReleaseDC, (FARPROC)extGDIReleaseDC}, + //{HOOK_IAT_CANDIDATE, "InvalidateRect", (FARPROC)InvalidateRect, (FARPROC *)&pInvalidateRect, (FARPROC)extInvalidateRect}, + {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator +}; + +static HookEntry_Type ScaledHooks[]={ + {HOOK_IAT_CANDIDATE, "DrawTextA", (FARPROC)DrawTextA, (FARPROC *)&pDrawText, (FARPROC)extDrawTextA}, + {HOOK_IAT_CANDIDATE, "DrawTextExA", (FARPROC)DrawTextExA, (FARPROC *)&pDrawTextEx, (FARPROC)extDrawTextExA}, + {HOOK_HOT_CANDIDATE, "FillRect", (FARPROC)NULL, (FARPROC *)&pFillRect, (FARPROC)extFillRect}, + {HOOK_IAT_CANDIDATE, "GetDC", (FARPROC)GetDC, (FARPROC *)&pGDIGetDC, (FARPROC)extGDIGetDC}, + {HOOK_IAT_CANDIDATE, "GetDCEx", (FARPROC)NULL, (FARPROC *)&pGDIGetDCEx, (FARPROC)extGDIGetDCEx}, + {HOOK_IAT_CANDIDATE, "GetWindowDC", (FARPROC)GetWindowDC, (FARPROC *)&pGDIGetWindowDC, (FARPROC)extGDIGetWindowDC}, + {HOOK_IAT_CANDIDATE, "ReleaseDC", (FARPROC)ReleaseDC, (FARPROC *)&pGDIReleaseDC, (FARPROC)extGDIReleaseDC}, + {HOOK_IAT_CANDIDATE, "ValidateRect", (FARPROC)ValidateRect, (FARPROC *)&pValidateRect, (FARPROC)extValidateRect}, + {HOOK_IAT_CANDIDATE, "ScrollWindow", (FARPROC)ScrollWindow, (FARPROC *)&pScrollWindow, (FARPROC)extScrollWindow}, + + {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator +}; + +static HookEntry_Type RemapHooks[]={ + {HOOK_HOT_CANDIDATE, "ScreenToClient", (FARPROC)ScreenToClient, (FARPROC *)&pScreenToClient, (FARPROC)extScreenToClient}, + {HOOK_HOT_CANDIDATE, "ClientToScreen", (FARPROC)ClientToScreen, (FARPROC *)&pClientToScreen, (FARPROC)extClientToScreen}, + {HOOK_HOT_CANDIDATE, "GetClientRect", (FARPROC)GetClientRect, (FARPROC *)&pGetClientRect, (FARPROC)extGetClientRect}, + {HOOK_HOT_CANDIDATE, "GetWindowRect", (FARPROC)GetWindowRect, (FARPROC *)&pGetWindowRect, (FARPROC)extGetWindowRect}, + {HOOK_HOT_CANDIDATE, "MapWindowPoints", (FARPROC)MapWindowPoints, (FARPROC *)&pMapWindowPoints, (FARPROC)extMapWindowPoints}, + {HOOK_HOT_CANDIDATE, "GetUpdateRgn", (FARPROC)GetUpdateRgn, (FARPROC *)&pGetUpdateRgn, (FARPROC)extGetUpdateRgn}, + //{HOOK_IAT_CANDIDATE, "GetUpdateRect", (FARPROC)GetUpdateRect, (FARPROC *)&pGetUpdateRect, (FARPROC)extGetUpdateRect}, + //{HOOK_IAT_CANDIDATE, "RedrawWindow", (FARPROC)RedrawWindow, (FARPROC *)&pRedrawWindow, (FARPROC)extRedrawWindow}, + {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator +}; + +static HookEntry_Type PeekAllHooks[]={ + {HOOK_IAT_CANDIDATE, "PeekMessageA", (FARPROC)NULL, (FARPROC *)&pPeekMessage, (FARPROC)extPeekMessage}, + {HOOK_IAT_CANDIDATE, "PeekMessageW", (FARPROC)NULL, (FARPROC *)&pPeekMessage, (FARPROC)extPeekMessage}, + {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator +}; + +static HookEntry_Type MouseHooks[]={ + {HOOK_HOT_CANDIDATE, "GetCursorPos", (FARPROC)GetCursorPos, (FARPROC *)&pGetCursorPos, (FARPROC)extGetCursorPos}, + {HOOK_HOT_CANDIDATE, "SetCursorPos", (FARPROC)SetCursorPos, (FARPROC *)&pSetCursorPos, (FARPROC)extSetCursorPos}, + {HOOK_IAT_CANDIDATE, "GetCursorInfo", (FARPROC)GetCursorInfo, (FARPROC *)&pGetCursorInfo, (FARPROC)extGetCursorInfo}, + {HOOK_IAT_CANDIDATE, "SetCursor", (FARPROC)SetCursor, (FARPROC *)&pSetCursor, (FARPROC)extSetCursor}, + {HOOK_IAT_CANDIDATE, "SendMessageA", (FARPROC)SendMessageA, (FARPROC *)&pSendMessageA, (FARPROC)extSendMessageA}, + {HOOK_IAT_CANDIDATE, "SendMessageW", (FARPROC)SendMessageW, (FARPROC *)&pSendMessageW, (FARPROC)extSendMessageW}, + //{HOOK_IAT_CANDIDATE, "SetPhysicalCursorPos", NULL, (FARPROC *)&pSetCursor, (FARPROC)extSetCursor}, // ??? + {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator +}; + +static HookEntry_Type WinHooks[]={ + {HOOK_HOT_CANDIDATE, "ShowWindow", (FARPROC)ShowWindow, (FARPROC *)&pShowWindow, (FARPROC)extShowWindow}, + {HOOK_HOT_CANDIDATE, "SetWindowPos", (FARPROC)SetWindowPos, (FARPROC *)&pSetWindowPos, (FARPROC)extSetWindowPos}, + {HOOK_HOT_CANDIDATE, "DeferWindowPos", (FARPROC)DeferWindowPos, (FARPROC *)&pGDIDeferWindowPos, (FARPROC)extDeferWindowPos}, + {HOOK_HOT_CANDIDATE, "CallWindowProcA", (FARPROC)CallWindowProcA, (FARPROC *)&pCallWindowProcA, (FARPROC)extCallWindowProcA}, + {HOOK_HOT_CANDIDATE, "CallWindowProcW", (FARPROC)CallWindowProcW, (FARPROC *)&pCallWindowProcW, (FARPROC)extCallWindowProcW}, + {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator +}; + +static HookEntry_Type TimeHooks[]={ + {HOOK_IAT_CANDIDATE, "SetTimer", (FARPROC)SetTimer, (FARPROC *)&pSetTimer, (FARPROC)extSetTimer}, + {HOOK_IAT_CANDIDATE, "KillTimer", (FARPROC)KillTimer, (FARPROC *)&pKillTimer, (FARPROC)extKillTimer}, + {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator +}; + +static HookEntry_Type DesktopHooks[]={ // currently unused, needed for X-Files + {HOOK_IAT_CANDIDATE, "CreateDesktopA", (FARPROC)CreateDesktopA, (FARPROC *)&pCreateDesktop, (FARPROC)extCreateDesktop}, + {HOOK_IAT_CANDIDATE, "SwitchDesktop", (FARPROC)SwitchDesktop, (FARPROC *)&pSwitchDesktop, (FARPROC)extSwitchDesktop}, + {HOOK_IAT_CANDIDATE, "OpenDesktopA", (FARPROC)OpenDesktopA, (FARPROC *)&pOpenDesktop, (FARPROC)extOpenDesktop}, + {HOOK_IAT_CANDIDATE, "CloseDesktop", (FARPROC)CloseDesktop, (FARPROC *)&pCloseDesktop, (FARPROC)extCloseDesktop}, + {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator +}; + +FARPROC Remap_user32_ProcAddress(LPCSTR proc, HMODULE hModule) +{ + FARPROC addr; + if (addr=RemapLibrary(proc, hModule, Hooks)) return addr; + if (dxw.dwFlags1 & CLIENTREMAPPING) if (addr=RemapLibrary(proc, hModule, RemapHooks)) return addr; + + if (dxw.dwFlags2 & GDISTRETCHED) + if (addr=RemapLibrary(proc, hModule, ScaledHooks)) return addr; + if (dxw.dwFlags3 & GDIEMULATEDC) + if (addr=RemapLibrary(proc, hModule, EmulateHooks)) return addr; + if (!(dxw.dwFlags2 & GDISTRETCHED) && !(dxw.dwFlags3 & GDIEMULATEDC)) + if (addr=RemapLibrary(proc, hModule, NoGDIHooks)) return addr; + if (dxw.dwFlags1 & (PREVENTMAXIMIZE|FIXWINFRAME|LOCKWINPOS|LOCKWINSTYLE)) + if (addr=RemapLibrary(proc, hModule, WinHooks)) return addr; + if ((dxw.dwFlags1 & (MODIFYMOUSE|SLOWDOWN|KEEPCURSORWITHIN)) || (dxw.dwFlags2 & KEEPCURSORFIXED)) + if (addr=RemapLibrary(proc, hModule, MouseHooks)) return addr; + if (dxw.dwFlags3 & PEEKALLMESSAGES) + if (addr=RemapLibrary(proc, hModule, PeekAllHooks)) return addr; + if((dxw.dwFlags2 & TIMESTRETCH) && (dxw.dwFlags4 & STRETCHTIMERS)) + if (addr=RemapLibrary(proc, hModule, TimeHooks)) return addr; + + return NULL; +} + +static char *libname = "user32.dll"; + +void HookUser32(HMODULE hModule) +{ + + HookLibrary(hModule, Hooks, libname); + if (!(dxw.dwFlags2 & GDISTRETCHED) && !(dxw.dwFlags3 & GDIEMULATEDC)) + HookLibrary(hModule, NoGDIHooks, libname); + if (dxw.dwFlags3 & GDIEMULATEDC) HookLibrary(hModule, EmulateHooks, libname); + if (dxw.dwFlags2 & GDISTRETCHED) HookLibrary(hModule, ScaledHooks, libname); + + if (dxw.dwFlags1 & CLIENTREMAPPING) HookLibrary(hModule, RemapHooks, libname); + if (dxw.dwFlags1 & (PREVENTMAXIMIZE|FIXWINFRAME|LOCKWINPOS|LOCKWINSTYLE)) HookLibrary(hModule, WinHooks, libname); + if ((dxw.dwFlags1 & (MODIFYMOUSE|SLOWDOWN|KEEPCURSORWITHIN)) || (dxw.dwFlags2 & KEEPCURSORFIXED)) HookLibrary(hModule, MouseHooks, libname); + if (dxw.dwFlags3 & PEEKALLMESSAGES) HookLibrary(hModule, PeekAllHooks, libname); + if (dxw.dwFlags2 & TIMESTRETCH) HookLibrary(hModule, TimeHooks, libname); + + IsChangeDisplaySettingsHotPatched = IsHotPatched(Hooks, "ChangeDisplaySettingsExA") || IsHotPatched(Hooks, "ChangeDisplaySettingsExW"); + return; +} + +void HookUser32Init() +{ + HookLibInit(Hooks); + HookLibInit(ScaledHooks); + HookLibInit(EmulateHooks); + HookLibInit(RemapHooks); + HookLibInit(MouseHooks); + HookLibInit(WinHooks); +} + +/* ------------------------------------------------------------------------------ */ +// auxiliary (static) functions +/* ------------------------------------------------------------------------------ */ + +static void Stopper(char *s, int line) +{ + char sMsg[81]; + sprintf(sMsg,"break: \"%s\"", s); + MessageBox(0, sMsg, "break", MB_OK | MB_ICONEXCLAMATION); +} + +//#define STOPPER_TEST // comment out to eliminate +#ifdef STOPPER_TEST +#define STOPPER(s) Stopper(s, __LINE__) +#else +#define STOPPER(s) +#endif + +static LPCSTR sTemplateName(LPCSTR tn) +{ + static char sBuf[20+1]; + if((DWORD)tn >> 16) + return tn; + else { + sprintf(sBuf, "ID:(%x)", ((DWORD)tn & 0x0000FFFF)); + return sBuf; + } +} + +// -------------------------------------------------------------------------- +// +// globals, externs, static functions... +// +// -------------------------------------------------------------------------- + +// PrimHDC: DC handle of the selected DirectDraw primary surface. NULL when invalid. +HDC PrimHDC=NULL; + +LPRECT lpClipRegion=NULL; +RECT ClipRegion; +int LastCurPosX, LastCurPosY; + +extern GetDC_Type pGetDC; +extern ReleaseDC_Type pReleaseDC; +//extern void FixWindowFrame(HWND); +extern HRESULT WINAPI sBlt(char *, LPDIRECTDRAWSURFACE, LPRECT, LPDIRECTDRAWSURFACE, LPRECT, DWORD, LPDDBLTFX, BOOL); + +LONG WINAPI MyChangeDisplaySettings(char *fname, BOOL WideChar, void *lpDevMode, DWORD dwflags) +{ + HRESULT res; + DWORD dmFields, dmBitsPerPel, dmPelsWidth, dmPelsHeight; + + if(dwflags & CDS_TEST) { + OutTraceDW("%s: TEST res=DISP_CHANGE_SUCCESSFUL\n", fname); + return DISP_CHANGE_SUCCESSFUL; + } + + // v2.02.32: reset the emulated DC used in GDIEMULATEDC mode + dxw.ResetEmulatedDC(); + + if(lpDevMode){ + if(WideChar){ + dmFields=((DEVMODEW *)lpDevMode)->dmFields; + dmPelsWidth=((DEVMODEW *)lpDevMode)->dmPelsWidth; + dmPelsHeight=((DEVMODEW *)lpDevMode)->dmPelsHeight; + dmBitsPerPel=((DEVMODEW *)lpDevMode)->dmBitsPerPel; + } + else{ + dmFields=((DEVMODEA *)lpDevMode)->dmFields; + dmPelsWidth=((DEVMODEA *)lpDevMode)->dmPelsWidth; + dmPelsHeight=((DEVMODEA *)lpDevMode)->dmPelsHeight; + dmBitsPerPel=((DEVMODEA *)lpDevMode)->dmBitsPerPel; + } + } + + // save desired settings first v.2.1.89 + // v2.1.95 protect when lpDevMode is null (closing game... Jedi Outcast) + // v2.2.23 consider new width/height only when dmFields flags are set. + if(lpDevMode && (dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT))){ + RECT client; + dxw.SetScreenSize(dmPelsWidth, dmPelsHeight); + + // v2.02.31: when main win is bigger that expected resolution, you're in windowed fullscreen mode + //(*pGetClientRect)((dxw.dwFlags1 & FIXPARENTWIN) ? dxw.hParentWnd : dxw.GethWnd(), &client); + (*pGetClientRect)(dxw.GethWnd(), &client); + OutTraceDW("%s: current hWnd=%x size=(%d,%d)\n", fname, dxw.GethWnd(), client.right, client.bottom); + if((client.right>=(LONG)dmPelsWidth) && (client.bottom>=(LONG)dmPelsHeight)) { + OutTraceDW("%s: entering FULLSCREEN mode\n", fname); + dxw.SetFullScreen(TRUE); + } + } + + if ((dwflags==0 || dwflags==CDS_FULLSCREEN) && lpDevMode){ + if (dxw.dwFlags1 & EMULATESURFACE || !(dmFields & DM_BITSPERPEL)){ + OutTraceDW("%s: BYPASS res=DISP_CHANGE_SUCCESSFUL\n", fname); + return DISP_CHANGE_SUCCESSFUL; + } + else{ + DEVMODEA NewMode; + if(dwflags==CDS_FULLSCREEN) dwflags=0; // no FULLSCREEN + (*pEnumDisplaySettings)(NULL, ENUM_CURRENT_SETTINGS, &NewMode); + OutTraceDW("ChangeDisplaySettings: CURRENT wxh=(%dx%d) BitsPerPel=%d -> %d\n", + NewMode.dmPelsWidth, NewMode.dmPelsHeight, NewMode.dmBitsPerPel, dmBitsPerPel); + NewMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + NewMode.dmBitsPerPel = dmBitsPerPel; + res=(*pChangeDisplaySettingsExA)(NULL, &NewMode, NULL, 0, NULL); + if(res) OutTraceE("ChangeDisplaySettings: ERROR err=%d at %d\n", GetLastError(), __LINE__); + return res; + } + } + else{ + if(WideChar) + return (*pChangeDisplaySettingsExW)(NULL, (LPDEVMODEW)lpDevMode, NULL, dwflags, NULL); + else + return (*pChangeDisplaySettingsExA)(NULL, (LPDEVMODEA)lpDevMode, NULL, dwflags, NULL); + } +} + +void dxwFixWindowPos(char *ApiName, HWND hwnd, LPARAM lParam) +{ + LPWINDOWPOS wp; + int MaxX, MaxY; + wp = (LPWINDOWPOS)lParam; + MaxX = dxw.iSizX; + MaxY = dxw.iSizY; + if (!MaxX) MaxX = dxw.GetScreenWidth(); + if (!MaxY) MaxY = dxw.GetScreenHeight(); + static int iLastCX, iLastCY; + static int BorderX=-1; + static int BorderY=-1; + int cx, cy; + extern void CalculateWindowPos(HWND, DWORD, DWORD, LPWINDOWPOS); + + OutTraceDW("%s: GOT hwnd=%x pos=(%d,%d) dim=(%d,%d) Flags=%x(%s)\n", + ApiName, hwnd, wp->x, wp->y, wp->cx, wp->cy, wp->flags, ExplainWPFlags(wp->flags)); + + if (dxw.dwFlags1 & PREVENTMAXIMIZE){ + int UpdFlag = 0; + WINDOWPOS MaxPos; + CalculateWindowPos(hwnd, MaxX, MaxY, &MaxPos); + + if(wp->cx>MaxPos.cx) { wp->cx=MaxPos.cx; UpdFlag=1; } + if(wp->cy>MaxPos.cy) { wp->cy=MaxPos.cy; UpdFlag=1; } + if (UpdFlag) + OutTraceDW("%s: SET max dim=(%d,%d)\n", ApiName, wp->cx, wp->cy); + } + + if ((wp->flags & (SWP_NOMOVE|SWP_NOSIZE))==(SWP_NOMOVE|SWP_NOSIZE)) return; //v2.02.13 + + if ((dxw.dwFlags1 & LOCKWINPOS) && dxw.IsFullScreen() && (hwnd==dxw.GethWnd())){ + CalculateWindowPos(hwnd, MaxX, MaxY, wp); + OutTraceDW("%s: LOCK pos=(%d,%d) dim=(%d,%d)\n", ApiName, wp->x, wp->y, wp->cx, wp->cy); + } + + if ((dxw.dwFlags2 & KEEPASPECTRATIO) && dxw.IsFullScreen() && (hwnd==dxw.GethWnd())){ + // note: while keeping aspect ration, resizing from one corner doesn't tell + // which coordinate is prevalent to the other. We made an arbitrary choice. + // note: v2.1.93: compensation must refer to the client area, not the wp + // window dimensions that include the window borders. + if(BorderX==-1){ + // v2.02.92: Fixed for AERO mode, where GetWindowRect substantially LIES! + RECT client, full; + LONG dwStyle, dwExStyle; + HMENU hMenu; + extern GetWindowLong_Type pGetWindowLongA; + (*pGetClientRect)(hwnd, &client); + full=client; + dwStyle=(*pGetWindowLongA)(hwnd, GWL_STYLE); + dwExStyle=(*pGetWindowLongA)(hwnd, GWL_EXSTYLE); + hMenu = (dwStyle & WS_CHILD) ? NULL : GetMenu(hwnd); + AdjustWindowRectEx(&full, dwStyle, (hMenu!=NULL), dwExStyle); + if (hMenu && (hMenu != (HMENU)-1)) __try {CloseHandle(hMenu);} __except(EXCEPTION_EXECUTE_HANDLER){}; + BorderX= full.right - full.left - client.right; + BorderY= full.bottom - full.top - client.bottom; + OutTraceDW("%s: KEEPASPECTRATIO window borders=(%d,%d)\n", ApiName, BorderX, BorderY); + } + extern LRESULT LastCursorPos; + switch (LastCursorPos){ + case HTBOTTOM: + case HTTOP: + case HTBOTTOMLEFT: + case HTBOTTOMRIGHT: + case HTTOPLEFT: + case HTTOPRIGHT: + cx = BorderX + ((wp->cy - BorderY) * dxw.iRatioX) / dxw.iRatioY; + if(cx!=wp->cx){ + OutTraceDW("%s: KEEPASPECTRATIO adjusted cx=%d->%d\n", ApiName, wp->cx, cx); + wp->cx = cx; + } + break; + case HTLEFT: + case HTRIGHT: + cy = BorderY + ((wp->cx - BorderX) * dxw.iRatioY) / dxw.iRatioX; + if(cy!=wp->cy){ + OutTraceDW("%s: KEEPASPECTRATIO adjusted cy=%d->%d\n", ApiName, wp->cy, cy); + wp->cy = cy; + } + break; + } + } + + if ((dxw.dwFlags5 & CENTERTOWIN) && dxw.IsFullScreen() && (hwnd==dxw.GethWnd())){ + RECT wrect; + LONG dwStyle, dwExStyle; + HMENU hMenu; + int minx, miny; + wrect = dxw.GetScreenRect(); + dwStyle=(*pGetWindowLongA)(hwnd, GWL_STYLE); + dwExStyle=(*pGetWindowLongA)(hwnd, GWL_EXSTYLE); + hMenu = (dwStyle & WS_CHILD) ? NULL : GetMenu(hwnd); + AdjustWindowRectEx(&wrect, dwStyle, (hMenu!=NULL), dwExStyle); + minx = wrect.right - wrect.left; + miny = wrect.bottom - wrect.top; + if(wp->cx < minx) wp->cx = minx; + if(wp->cy < miny) wp->cy = miny; + } + + iLastCX= wp->cx; + iLastCY= wp->cy; +} + +void dxwFixMinMaxInfo(char *ApiName, HWND hwnd, LPARAM lParam) +{ + if (dxw.dwFlags1 & PREVENTMAXIMIZE){ + LPMINMAXINFO lpmmi; + lpmmi=(LPMINMAXINFO)lParam; + OutTraceDW("%s: GOT MaxPosition=(%d,%d) MaxSize=(%d,%d)\n", ApiName, + lpmmi->ptMaxPosition.x, lpmmi->ptMaxPosition.y, lpmmi->ptMaxSize.x, lpmmi->ptMaxSize.y); + lpmmi->ptMaxPosition.x=0; + lpmmi->ptMaxPosition.y=0; + lpmmi->ptMaxSize.x = dxw.GetScreenWidth(); + lpmmi->ptMaxSize.y = dxw.GetScreenHeight(); + + OutTraceDW("%s: SET PREVENTMAXIMIZE MaxPosition=(%d,%d) MaxSize=(%d,%d)\n", ApiName, + lpmmi->ptMaxPosition.x, lpmmi->ptMaxPosition.y, lpmmi->ptMaxSize.x, lpmmi->ptMaxSize.y); + } + + // v2.1.75: added logic to fix win coordinates to selected ones. + // fixes the problem with "Achtung Spitfire", that can't be managed through PREVENTMAXIMIZE flag. + if (dxw.dwFlags1 & LOCKWINPOS){ + LPMINMAXINFO lpmmi; + lpmmi=(LPMINMAXINFO)lParam; + OutTraceDW("%s: GOT MaxPosition=(%d,%d) MaxSize=(%d,%d)\n", ApiName, + lpmmi->ptMaxPosition.x, lpmmi->ptMaxPosition.y, lpmmi->ptMaxSize.x, lpmmi->ptMaxSize.y); + lpmmi->ptMaxPosition.x=dxw.iPosX; + lpmmi->ptMaxPosition.y=dxw.iPosY; + lpmmi->ptMaxSize.x = dxw.iSizX ? dxw.iSizX : dxw.GetScreenWidth(); + lpmmi->ptMaxSize.y = dxw.iSizY ? dxw.iSizY : dxw.GetScreenHeight(); + OutTraceDW("%s: SET LOCKWINPOS MaxPosition=(%d,%d) MaxSize=(%d,%d)\n", ApiName, + lpmmi->ptMaxPosition.x, lpmmi->ptMaxPosition.y, lpmmi->ptMaxSize.x, lpmmi->ptMaxSize.y); + } +} + +static LRESULT WINAPI FixWindowProc(char *ApiName, HWND hwnd, UINT Msg, WPARAM wParam, LPARAM *lpParam) +{ + LPARAM lParam; + + lParam=*lpParam; + OutTraceW("%s: hwnd=%x msg=[0x%x]%s(%x,%x)\n", + ApiName, hwnd, Msg, ExplainWinMessage(Msg), wParam, lParam); + + switch(Msg){ + case WM_NCHITTEST: + // v2.02.71 fix: when processing WM_NCHITTEST messages whith fixed coordinates avoid calling + // the *pDefWindowProc call + // fixes "Microsoft Motocross Madness" mouse handling + if((dxw.dwFlags2 & FIXNCHITTEST) && (dxw.dwFlags1 & MODIFYMOUSE)){ // mouse processing + OutTraceDW("%s: suppress WM_NCHITTEST\n", ApiName); + return TRUE; + } + break; + case WM_ERASEBKGND: + OutTraceDW("%s: prevent erase background\n", ApiName); + return TRUE; // 1=erased + break; // useless + case WM_GETMINMAXINFO: + dxwFixMinMaxInfo(ApiName, hwnd, lParam); + break; + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: + dxwFixWindowPos(ApiName, hwnd, lParam); + break; + case WM_STYLECHANGING: + case WM_STYLECHANGED: + dxw.FixStyle(ApiName, hwnd, wParam, lParam); + break; + case WM_SIZE: + if ((dxw.dwFlags1 & LOCKWINPOS) && dxw.IsFullScreen()) return 0; + if (dxw.dwFlags1 & PREVENTMAXIMIZE){ + if ((wParam == SIZE_MAXIMIZED)||(wParam == SIZE_MAXSHOW)){ + OutTraceDW("%s: prevent screen SIZE to fullscreen wparam=%d(%s) size=(%d,%d)\n", ApiName, + wParam, ExplainResizing(wParam), HIWORD(lParam), LOWORD(lParam)); + return 0; // checked + //lParam = MAKELPARAM(dxw.GetScreenWidth(), dxw.GetScreenHeight()); + //OutTraceDW("%s: updated SIZE wparam=%d(%s) size=(%d,%d)\n", ApiName, + // wParam, ExplainResizing(wParam), HIWORD(lParam), LOWORD(lParam)); + } + } + break; + default: + break; + } + + // marker to run hooked function + return(-1); +} + +// -------------------------------------------------------------------------- +// +// user32 API hookers +// +// -------------------------------------------------------------------------- + + +BOOL WINAPI extInvalidateRect(HWND hwnd, RECT *lpRect, BOOL bErase) +{ + if(IsTraceDW){ + char sRect[81]; + if(lpRect) sprintf(sRect, "(%d,%d)-(%d,%d)", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + else strcpy(sRect, "NULL"); + OutTrace("InvalidateRect: hwnd=%x rect=%s erase=%x\n", hwnd, sRect, bErase); + } + + if(dxw.IsFullScreen()) { + if(dxw.dwFlags6 & SHAREDDC){ // Deadlock 2 + if(lpRect) dxw.MapClient(lpRect); + return (*pInvalidateRect)(hwnd, lpRect, bErase); + } + switch(dxw.GDIEmulationMode){ + case GDIMODE_STRETCHED: + case GDIMODE_SHAREDDC: + if(lpRect) dxw.MapClient(lpRect); + break; + case GDIMODE_EMULATED: + default: + break; + } + } + + return (*pInvalidateRect)(hwnd, lpRect, bErase); +} + +BOOL WINAPI extShowWindow(HWND hwnd, int nCmdShow) +{ + BOOL res; + + OutTraceDW("ShowWindow: hwnd=%x, CmdShow=%x(%s)\n", hwnd, nCmdShow, ExplainShowCmd(nCmdShow)); + if (dxw.dwFlags1 & PREVENTMAXIMIZE){ + if(nCmdShow==SW_MAXIMIZE){ + OutTraceDW("ShowWindow: suppress SW_MAXIMIZE maximize\n"); + nCmdShow=SW_SHOWNORMAL; + } + if(nCmdShow==SW_SHOWDEFAULT){ + STARTUPINFO StartupInfo; + GetStartupInfo(&StartupInfo); + OutTraceDW("DEBUG: StartupInfo dwFlags=%x ShowWindow=%x\n", StartupInfo.dwFlags, StartupInfo.wShowWindow); + if((StartupInfo.dwFlags & STARTF_USESHOWWINDOW) && (StartupInfo.wShowWindow == SW_MAXIMIZE)){ + OutTraceDW("ShowWindow: suppress SW_SHOWDEFAULT maximize\n"); + nCmdShow=SW_SHOWNORMAL; + } + } + } + + res=(*pShowWindow)(hwnd, nCmdShow); + OutTraceDW("ShowWindow: res=%x\n", res); + + return res; +} + +LONG WINAPI extGetWindowLong(GetWindowLong_Type pGetWindowLong, char *ApiName, HWND hwnd, int nIndex) +{ + LONG res; + + res=(*pGetWindowLong)(hwnd, nIndex); + + OutTraceB("%s: hwnd=%x, Index=%x(%s) res=%x\n", ApiName, hwnd, nIndex, ExplainSetWindowIndex(nIndex), res); + + if((nIndex==GWL_WNDPROC)||(nIndex==DWL_DLGPROC)){ + WNDPROC wp; + wp=dxwws.GetProc(hwnd); + OutTraceDW("%s: remapping WindowProc res=%x -> %x\n", ApiName, res, (LONG)wp); + if(wp) res=(LONG)wp; // if not found, don't alter the value. + } + + return res; +} + +LONG WINAPI extGetWindowLongA(HWND hwnd, int nIndex) +{ + return extGetWindowLong(pGetWindowLongA, "GetWindowLongA", hwnd, nIndex); +} + +LONG WINAPI extGetWindowLongW(HWND hwnd, int nIndex) +{ + return extGetWindowLong(pGetWindowLongW, "GetWindowLongW", hwnd, nIndex); +} + +LONG WINAPI extSetWindowLong(HWND hwnd, int nIndex, LONG dwNewLong, SetWindowLong_Type pSetWindowLong) +{ + LONG res; + + OutTraceDW("SetWindowLong: hwnd=%x, Index=%x(%s) Val=%x\n", + hwnd, nIndex, ExplainSetWindowIndex(nIndex), dwNewLong); + + if (dxw.Windowize){ + if(dxw.dwFlags1 & LOCKWINSTYLE){ + if(nIndex==GWL_STYLE){ + OutTraceDW("SetWindowLong: Lock GWL_STYLE=%x\n", dwNewLong); + return (*pGetWindowLongA)(hwnd, nIndex); + } + if(nIndex==GWL_EXSTYLE){ + OutTraceDW("SetWindowLong: Lock GWL_EXSTYLE=%x\n", dwNewLong); + return (*pGetWindowLongA)(hwnd, nIndex); + } + } + + if (dxw.dwFlags1 & PREVENTMAXIMIZE){ + if(nIndex==GWL_STYLE){ + dwNewLong &= ~WS_MAXIMIZE; + if(dxw.IsDesktop(hwnd)){ + OutTraceDW("SetWindowLong: GWL_STYLE %x suppress MAXIMIZE\n", dwNewLong); + dwNewLong |= WS_OVERLAPPEDWINDOW; + dwNewLong &= ~(WS_DLGFRAME|WS_MAXIMIZE|WS_VSCROLL|WS_HSCROLL|WS_CLIPSIBLINGS); + } + } + // v2.02.32: disable topmost for main window only + if(dxw.IsDesktop(hwnd) && (nIndex==GWL_EXSTYLE)){ + OutTraceDW("SetWindowLong: GWL_EXSTYLE %x suppress TOPMOST\n", dwNewLong); + dwNewLong = dwNewLong & ~(WS_EX_TOPMOST); + } + } + + if (dxw.dwFlags1 & FIXWINFRAME){ + //if((nIndex==GWL_STYLE) && !(dwNewLong & WS_CHILD)){ + if((nIndex==GWL_STYLE) && !(dwNewLong & WS_CHILD) && dxw.IsDesktop(hwnd)){ + OutTraceDW("SetWindowLong: GWL_STYLE %x force OVERLAPPEDWINDOW\n", dwNewLong); + dwNewLong |= WS_OVERLAPPEDWINDOW; + dwNewLong &= ~WS_CLIPSIBLINGS; + } + } + } + + if (((nIndex==GWL_WNDPROC)||(nIndex==DWL_DLGPROC)) && + dxw.IsFullScreen() && // v2.02.51 - see A10 Cuba.... + !(dxw.dwFlags6 & NOWINDOWHOOKS)){ // v2.03.41 - debug flag + WNDPROC lres; + WNDPROC OldProc; + // GPL fix + if(dxw.IsRealDesktop(hwnd) && dxw.Windowize) { + hwnd=dxw.GethWnd(); + OutTraceDW("SetWindowLong: DESKTOP hwnd, FIXING hwnd=%x\n",hwnd); + } + // end of GPL fix + + OldProc = (WNDPROC)(*pGetWindowLongA)(hwnd, nIndex); + // v2.02.70 fix + if((OldProc==extWindowProc) || + (OldProc==extChildWindowProc)|| + (OldProc==extDialogWindowProc)) + OldProc=dxwws.GetProc(hwnd); + dxwws.PutProc(hwnd, (WNDPROC)dwNewLong); + res=(LONG)OldProc; + SetLastError(0); + lres=(WNDPROC)(*pSetWindowLongA)(hwnd, nIndex, (LONG)extWindowProc); + if(!lres && GetLastError())OutTraceE("SetWindowLong: ERROR err=%d at %d\n", GetLastError(), __LINE__); + } + else { + res=(*pSetWindowLongA)(hwnd, nIndex, dwNewLong); + } + + OutTraceDW("SetWindowLong: hwnd=%x, nIndex=%x, Val=%x, res=%x\n", hwnd, nIndex, dwNewLong, res); + return res; +} + +LONG WINAPI extSetWindowLongA(HWND hwnd, int nIndex, LONG dwNewLong) +{ + return extSetWindowLong(hwnd, nIndex, dwNewLong, pSetWindowLongA); +} + +LONG WINAPI extSetWindowLongW(HWND hwnd, int nIndex, LONG dwNewLong) +{ + return extSetWindowLong(hwnd, nIndex, dwNewLong, pSetWindowLongW); +} + +BOOL WINAPI extSetWindowPos(HWND hwnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags) +{ + BOOL res; + + OutTraceDW("SetWindowPos: hwnd=%x%s pos=(%d,%d) dim=(%d,%d) Flags=%x\n", + hwnd, dxw.IsFullScreen()?"(FULLSCREEN)":"", X, Y, cx, cy, uFlags); + + // when not in fullscreen mode, just proxy the call + if (!dxw.IsFullScreen()){ + res=(*pSetWindowPos)(hwnd, hWndInsertAfter, X, Y, cx, cy, uFlags); + if(!res)OutTraceE("SetWindowPos: ERROR err=%d at %d\n", GetLastError(), __LINE__); + return res; + } + + // in fullscreen, but a child window inside ..... + if (!dxw.IsDesktop(hwnd)){ + RECT r; + r.left = X; + r.right = X + cx; + r.top = Y; + r.bottom = Y + cy; + if ((*pGetWindowLongA)(hwnd, GWL_STYLE) & WS_CHILD){ + r = dxw.MapClientRect(&r); + } + else { + //r = dxw.MapWindowRect(&r); + } + X = r.left; + Y = r.top; + cx = r.right - r.left; + cy = r.bottom - r.top; + + res=(*pSetWindowPos)(hwnd, hWndInsertAfter, X, Y, cx, cy, uFlags); + if(!res)OutTraceE("SetWindowPos: ERROR err=%d at %d\n", GetLastError(), __LINE__); + + //HFONT hFont; + //hFont=CreateFont ( + // 30, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, + // FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, + // DEFAULT_PITCH | FF_SWISS, NULL); // "Arial"); + //SendMessage (hwnd, WM_SETFONT, WPARAM (hFont), TRUE); + + return res; + } + + if (dxw.dwFlags1 & LOCKWINPOS){ + // Note: any attempt to change the window position, no matter where and how, through the + // SetWindowPos API is causing resizing to the default 1:1 pixed size in Commandos. + // in such cases, there is incompatibility between LOCKWINPOS and LOCKWINSTYLE. + OutTraceDW("SetWindowPos: locked position\n"); + return 1; + } + + if (dxw.dwFlags1 & PREVENTMAXIMIZE){ + int UpdFlag =0; + int MaxX, MaxY; + MaxX = dxw.iSizX; + MaxY = dxw.iSizY; + if (!MaxX) MaxX = dxw.GetScreenWidth(); + if (!MaxY) MaxY = dxw.GetScreenHeight(); + if(cx>MaxX) { cx=MaxX; UpdFlag=1; } + if(cy>MaxY) { cy=MaxY; UpdFlag=1; } + if (UpdFlag) + OutTraceDW("SetWindowPos: using max dim=(%d,%d)\n", cx, cy); + } + + // useful??? to be demonstrated.... + // when altering main window in fullscreen mode, fix the coordinates for borders + DWORD dwCurStyle, dwExStyle; + HMENU hMenu; + RECT rect; + rect.top=rect.left=0; + rect.right=cx; rect.bottom=cy; + dwCurStyle=(*pGetWindowLongA)(hwnd, GWL_STYLE); + dwExStyle=(*pGetWindowLongA)(hwnd, GWL_EXSTYLE); + // BEWARE: from MSDN - If the window is a child window, the return value is undefined. + hMenu = (dwCurStyle & WS_CHILD) ? NULL : GetMenu(hwnd); + AdjustWindowRectEx(&rect, dwCurStyle, (hMenu!=NULL), dwExStyle); + if (hMenu && (hMenu != (HMENU)-1)) __try {CloseHandle(hMenu);} __except(EXCEPTION_EXECUTE_HANDLER){}; + cx=rect.right; cy=rect.bottom; + OutTraceDW("SetWindowPos: main form hwnd=%x fixed size=(%d,%d)\n", hwnd, cx, cy); + + res=(*pSetWindowPos)(hwnd, hWndInsertAfter, X, Y, cx, cy, uFlags); + if(!res)OutTraceE("SetWindowPos: ERROR err=%d at %d\n", GetLastError(), __LINE__); + return res; +} + +HDWP WINAPI extDeferWindowPos(HDWP hWinPosInfo, HWND hwnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags) +{ + // v2.02.31: heavily used by "Imperialism II" !!! + HDWP res; + + OutTraceDW("DeferWindowPos: hwnd=%x%s pos=(%d,%d) dim=(%d,%d) Flags=%x\n", + hwnd, dxw.IsFullScreen()?"(FULLSCREEN)":"", X, Y, cx, cy, uFlags); + + if(dxw.IsFullScreen()){ + dxw.MapClient(&X, &Y, &cx, &cy); + OutTraceDW("DeferWindowPos: remapped pos=(%d,%d) dim=(%d,%d)\n", X, Y, cx, cy); + } + + res=(*pGDIDeferWindowPos)(hWinPosInfo, hwnd, hWndInsertAfter, X, Y, cx, cy, uFlags); + if(!res)OutTraceE("DeferWindowPos: ERROR err=%d at %d\n", GetLastError(), __LINE__); + return res; +} + +LRESULT WINAPI extSendMessage(char *apiname, SendMessage_Type pSendMessage, HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + LRESULT ret; + OutTraceW("%s: hwnd=%x WinMsg=[0x%x]%s(%x,%x)\n", + apiname, hwnd, Msg, ExplainWinMessage(Msg), wParam, lParam); + + if(dxw.dwFlags1 & MODIFYMOUSE){ + switch (Msg){ + case WM_MOUSEMOVE: + case WM_MOUSEWHEEL: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MBUTTONDBLCLK: + // revert here the WindowProc mouse correction + POINT prev, curr; + RECT rect; + prev.x = LOWORD(lParam); + prev.y = HIWORD(lParam); + (*pGetClientRect)(dxw.GethWnd(), &rect); + curr.x = (prev.x * rect.right) / dxw.GetScreenWidth(); + curr.y = (prev.y * rect.bottom) / dxw.GetScreenHeight(); + if (Msg == WM_MOUSEWHEEL){ // v2.02.33 mousewheel fix + POINT upleft={0,0}; + (*pClientToScreen)(dxw.GethWnd(), &upleft); + curr = dxw.AddCoordinates(curr, upleft); + } + lParam = MAKELPARAM(curr.x, curr.y); + OutTraceC("%s: hwnd=%x pos XY=(%d,%d)->(%d,%d)\n", apiname, hwnd, prev.x, prev.y, curr.x, curr.y); + break; + default: + break; + } + } + ret=(*pSendMessage)(hwnd, Msg, wParam, lParam); + OutTraceW("%s: lresult=%x\n", apiname, ret); + return ret; +} + +LRESULT WINAPI extSendMessageA(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + return extSendMessage("SendMessageA", pSendMessageA, hwnd, Msg, wParam, lParam); +} + +LRESULT WINAPI extSendMessageW(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + return extSendMessage("SendMessageW", pSendMessageW, hwnd, Msg, wParam, lParam); +} + +HCURSOR WINAPI extSetCursor(HCURSOR hCursor) +{ + HCURSOR ret; + + ret=(*pSetCursor)(hCursor); + OutTraceDW("GDI.SetCursor: Cursor=%x, ret=%x\n", hCursor, ret); + //MessageBox(0, "SelectPalette", "GDI32.dll", MB_OK | MB_ICONEXCLAMATION); + return ret; +} + +BOOL WINAPI extGetCursorPos(LPPOINT lppoint) +{ + HRESULT res; + static int PrevX, PrevY; + POINT prev; + + if(dxw.dwFlags1 & SLOWDOWN) dxw.DoSlow(2); + + if (pGetCursorPos) { + res=(*pGetCursorPos)(lppoint); + } + else { + lppoint->x =0; lppoint->y=0; + res=1; + } + + prev=*lppoint; + *lppoint=dxw.ScreenToClient(*lppoint); + *lppoint=dxw.FixCursorPos(*lppoint); + + GetHookInfo()->CursorX=(short)lppoint->x; + GetHookInfo()->CursorY=(short)lppoint->y; + OutTraceC("GetCursorPos: FIXED pos=(%d,%d)->(%d,%d)\n", prev.x, prev.y, lppoint->x, lppoint->y); + + return res; +} + +BOOL WINAPI extSetCursorPos(int x, int y) +{ + BOOL res; + int PrevX, PrevY; + + PrevX=x; + PrevY=y; + + if(dxw.dwFlags2 & KEEPCURSORFIXED) { + OutTraceC("SetCursorPos: FIXED pos=(%d,%d)\n", x, y); + LastCurPosX=x; + LastCurPosY=y; + return 1; + } + + if(dxw.dwFlags1 & SLOWDOWN) dxw.DoSlow(2); + + if(dxw.dwFlags1 & KEEPCURSORWITHIN){ + // Intercept SetCursorPos outside screen boundaries (used as Cursor OFF in some games) + if ((y<0)||(y>=(int)dxw.GetScreenHeight())||(x<0)||(x>=(int)dxw.GetScreenWidth())) return 1; + } + + if(dxw.dwFlags1 & MODIFYMOUSE){ + // v2.03.41 + POINT cur; + cur.x = x; + cur.y = y; + dxw.MapWindow(&cur); + x = cur.x; + y = cur.y; + } + + res=0; + if (pSetCursorPos) res=(*pSetCursorPos)(x,y); + + OutTraceC("SetCursorPos: res=%x XY=(%d,%d)->(%d,%d)\n", res, PrevX, PrevY, x, y); + return res; +} + +BOOL WINAPI extPeekMessage(LPMSG lpMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg) +{ + BOOL res; + + if((wMsgFilterMin==0) && (wMsgFilterMax == 0)){ + // no filtering, everything is good + res=(*pPeekMessage)(lpMsg, hwnd, wMsgFilterMin, wMsgFilterMax, (wRemoveMsg & 0x000F)); + } + else { + MSG Dummy; + // better eliminate all messages before and after the selected range !!!! + //if(wMsgFilterMin)(*pPeekMessage)(&Dummy, hwnd, 0, wMsgFilterMin-1, TRUE); + if(wMsgFilterMin>0x0F)(*pPeekMessage)(&Dummy, hwnd, 0x0F, wMsgFilterMin-1, TRUE); + res=(*pPeekMessage)(lpMsg, hwnd, wMsgFilterMin, wMsgFilterMax, (wRemoveMsg & 0x000F)); + if(wMsgFilterMaxhwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg, ExplainPeekRemoveMsg(wRemoveMsg), + lpMsg->message, ExplainWinMessage(lpMsg->message & 0xFFFF), + lpMsg->wParam, lpMsg->lParam, lpMsg->pt.x, lpMsg->pt.y, res); + else + OutTraceW("PeekMessage: ANY lpmsg=%x hwnd=%x filter=(%x-%x) remove=%x(%s) res=%x\n", + lpMsg, lpMsg->hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg, ExplainPeekRemoveMsg(wRemoveMsg), res); + + + return res; +} + +BOOL WINAPI extClientToScreen(HWND hwnd, LPPOINT lppoint) +{ + // v2.02.10: fully revised to handle scaled windows + BOOL res; + + OutTraceB("ClientToScreen: hwnd=%x hWnd=%x FullScreen=%x point=(%d,%d)\n", + hwnd, dxw.GethWnd(), dxw.IsFullScreen(), lppoint->x, lppoint->y); + if (lppoint && dxw.IsFullScreen()){ + // optimization: in fullscreen mode, coordinate conversion for the desktop window + // should always keep the same values inaltered + if(hwnd != dxw.GethWnd()){ + *lppoint = dxw.AddCoordinates(*lppoint, dxw.ClientOffset(hwnd)); + } + OutTraceB("ClientToScreen: FIXED point=(%d,%d)\n", lppoint->x, lppoint->y); + res=TRUE; + } + else { + res=(*pClientToScreen)(hwnd, lppoint); + } + return res; +} + +BOOL WINAPI extScreenToClient(HWND hwnd, LPPOINT lppoint) +{ + // v2.02.10: fully revised to handle scaled windows + BOOL res; + OutTraceB("ScreenToClient: hwnd=%x hWnd=%x FullScreen=%x point=(%d,%d)\n", + hwnd, dxw.GethWnd(), dxw.IsFullScreen(), lppoint->x, lppoint->y); + + if (lppoint && (lppoint->x == -32000) && (lppoint->y == -32000)) return 1; + + if (lppoint && dxw.IsFullScreen()){ + // optimization: in fullscreen mode, coordinate conversion for the desktop window + // should always keep the same values inaltered + if(hwnd != dxw.GethWnd()){ + *lppoint = dxw.SubCoordinates(*lppoint, dxw.ClientOffset(hwnd)); + OutTraceB("ScreenToClient: FIXED point=(%d,%d)\n", lppoint->x, lppoint->y); + } + res=TRUE; + } + else { + res=(*pScreenToClient)(hwnd, lppoint); + } + return res; +} + +BOOL WINAPI extGetClientRect(HWND hwnd, LPRECT lpRect) +{ + BOOL ret; + OutTraceB("GetClientRect: whnd=%x FullScreen=%x\n", hwnd, dxw.IsFullScreen()); + + if(!lpRect) return 0; + + // proxed call + ret=(*pGetClientRect)(hwnd, lpRect); + if(!ret) { + OutTraceE("GetClientRect: ERROR hwnd=%x err=%d at %d\n", hwnd, GetLastError(), __LINE__); + return ret; + } + OutTraceB("GetClientRect: actual rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + + if (dxw.IsDesktop(hwnd)){ + *lpRect = dxw.GetScreenRect(); + OutTraceB("GetClientRect: desktop rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + else + if (dxw.IsFullScreen()){ + int w, h; + if(FIXCHILDSIZE){ + if(dxwws.GetSize(hwnd, &w, &h)){ + lpRect->top=lpRect->left=0; + lpRect->right=w; + lpRect->bottom=h; + OutTraceB("GetClientRect: fixed rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + return TRUE; + } + } + *lpRect=dxw.GetClientRect(*lpRect); + OutTraceB("GetClientRect: fixed rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + return ret; +} + +BOOL WINAPI extGetWindowRect(HWND hwnd, LPRECT lpRect) +{ + BOOL ret; + OutTraceB("GetWindowRect: hwnd=%x hWnd=%x FullScreen=%x\n", hwnd, dxw.GethWnd(), dxw.IsFullScreen()); + + if(dxw.IsRealDesktop(hwnd)) hwnd = dxw.GethWnd(); // v2.03.52: fix for "Storm Angel" + + ret=(*pGetWindowRect)(hwnd, lpRect); + if(!ret) { + OutTraceE("GetWindowRect: GetWindowRect hwnd=%x error %d at %d\n", hwnd, GetLastError(), __LINE__); + return ret; + } + OutTraceB("GetWindowRect: rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + + // minimized windows behaviour + if((lpRect->left == -32000)||(lpRect->top == -32000)) return ret; + + if (dxw.IsDesktop(hwnd)){ + // to avoid keeping track of window frame + *lpRect = dxw.GetScreenRect(); + OutTraceB("GetWindowRect: desktop rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + else + if (dxw.IsFullScreen()){ + *lpRect=dxw.GetWindowRect(*lpRect); + + // Diablo fix: it retrieves coordinates for the explorer window, that are as big as the real desktop!!! + if(lpRect->left < 0) lpRect->left=0; +// if(lpRect->left > (LONG)dxw.GetScreenWidth()) lpRect->left=dxw.GetScreenWidth(); +// if(lpRect->right < 0) lpRect->right=0; + if(lpRect->right > (LONG)dxw.GetScreenWidth()) lpRect->right=dxw.GetScreenWidth(); + if(lpRect->top < 0) lpRect->top=0; +// if(lpRect->top > (LONG)dxw.GetScreenHeight()) lpRect->top=dxw.GetScreenHeight(); +// if(lpRect->bottom < 0) lpRect->bottom=0; + if(lpRect->bottom > (LONG)dxw.GetScreenHeight()) lpRect->bottom=dxw.GetScreenHeight(); + + OutTraceB("GetWindowRect: fixed rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + + return ret; +} + +int WINAPI extMapWindowPoints(HWND hWndFrom, HWND hWndTo, LPPOINT lpPoints, UINT cPoints) +{ + UINT pi; + int ret; + // a rarely used API, but responsible for a painful headache: needs hooking for "Commandos 2", "Alien Nations". + // used also in "Full Pipe" activemovie + // used also in "NBA Live 99" menu screen + + OutTraceDW("MapWindowPoints: hWndFrom=%x%s hWndTo=%x%s cPoints=%d FullScreen=%x\n", + hWndFrom, dxw.IsDesktop(hWndFrom)?"(DESKTOP)":"", + hWndTo, dxw.IsDesktop(hWndTo)?"(DESKTOP)":"", + cPoints, dxw.IsFullScreen()); + if(IsDebug){ + OutTrace("Points: "); + for(pi=0; pi>16, ret&0x0000FFFF); + return ret; +} + +HWND WINAPI extGetDesktopWindow(void) +{ + HWND res; + + if((!dxw.Windowize) || (dxw.dwFlags5 & DIABLOTWEAK)) { + HWND ret; + ret = (*pGetDesktopWindow)(); + OutTraceDW("GetDesktopWindow: BYPASS ret=%x\n", ret); + return ret; + } + + OutTraceDW("GetDesktopWindow: FullScreen=%x\n", dxw.IsFullScreen()); + if (dxw.IsFullScreen()){ + if(dxw.dwFlags6 & CREATEDESKTOP){ + extern HWND hDesktopWindow; + OutTraceDW("GetDesktopWindow: returning desktop emulated hwnd=%x\n", hDesktopWindow); + return hDesktopWindow; + } + OutTraceDW("GetDesktopWindow: returning main window hwnd=%x\n", dxw.GethWnd()); + return dxw.GethWnd(); + } + else{ + res=(*pGetDesktopWindow)(); + OutTraceDW("GetDesktopWindow: returning desktop window hwnd=%x\n", res); + return res; + } +} + +int WINAPI extGetSystemMetrics(int nindex) +{ + HRESULT res; + + res=(*pGetSystemMetrics)(nindex); + OutTraceDW("GetSystemMetrics: index=%x(%s), res=%d\n", nindex, ExplainsSystemMetrics(nindex), res); + + if(!dxw.Windowize){ + // v2.02.95: if not in window mode, just implement the HIDEMULTIMONITOR flag + if( (nindex ==SM_CMONITORS) && + (dxw.dwFlags2 & HIDEMULTIMONITOR) && + res>1) { + res=1; + OutTraceDW("GetSystemMetrics: fix SM_CMONITORS=%d\n", res); + } + return res; + } + + switch(nindex){ + case SM_CXFULLSCREEN: + case SM_CXSCREEN: + case SM_CXVIRTUALSCREEN: // v2.02.31 + res= dxw.GetScreenWidth(); + OutTraceDW("GetSystemMetrics: fix SM_CXSCREEN=%d\n", res); + break; + case SM_CYFULLSCREEN: + case SM_CYSCREEN: + case SM_CYVIRTUALSCREEN: // v2.02.31 + res= dxw.GetScreenHeight(); + OutTraceDW("GetSystemMetrics: fix SM_CYSCREEN=%d\n", res); + break; + case SM_CMONITORS: + if((dxw.dwFlags2 & HIDEMULTIMONITOR) && res>1) { + res=1; + OutTraceDW("GetSystemMetrics: fix SM_CMONITORS=%d\n", res); + } + break; + } + + return res; +} + +ATOM WINAPI extRegisterClassExA(WNDCLASSEX *lpwcx) +{ + OutTraceDW("RegisterClassEx: PROXED ClassName=%s style=%x(%s) WndProc=%x cbClsExtra=%d cbWndExtra=%d hInstance=%x\n", + lpwcx->lpszClassName, lpwcx->style, ExplainStyle(lpwcx->style), lpwcx->lpfnWndProc, lpwcx->cbClsExtra, lpwcx->cbWndExtra, lpwcx->hInstance); + return (*pRegisterClassExA)(lpwcx); +} + +ATOM WINAPI extRegisterClassA(WNDCLASS *lpwcx) +{ + // referenced by Syberia, together with RegisterClassExA + OutTraceDW("RegisterClass: PROXED ClassName=%s style=%x(%s) WndProc=%x cbClsExtra=%d cbWndExtra=%d hInstance=%x\n", + lpwcx->lpszClassName, lpwcx->style, ExplainStyle(lpwcx->style), lpwcx->lpfnWndProc, lpwcx->cbClsExtra, lpwcx->cbWndExtra, lpwcx->hInstance); + return (*pRegisterClassA)(lpwcx); +} + +static void HookChildWndProc(HWND hwnd, DWORD dwStyle, LPCTSTR ApiName) +{ + // child window inherit the father's windproc, so if it's redirected to + // a hooker (either extWindowProc or extChildWindowProc) you have to retrieve + // the correct value (dxwws.GetProc) before saving it (dxwws.PutProc). + long res; + WNDPROC pWindowProc; + + if(dxw.dwFlags6 & NOWINDOWHOOKS) return; + + pWindowProc = (WNDPROC)(*pGetWindowLongA)(hwnd, GWL_WNDPROC); + if((pWindowProc == extWindowProc) || + (pWindowProc == extChildWindowProc) || + (pWindowProc == extDialogWindowProc)){ // avoid recursions + HWND Father; + WNDPROC pFatherProc; + Father=(*pGetParent)(hwnd); + pFatherProc=dxwws.GetProc(Father); + OutTraceDW("%s: WndProc=%s father=%x WndProc=%x\n", ApiName, + (pWindowProc == extWindowProc) ? "extWindowProc" : ((pWindowProc == extChildWindowProc) ? "extChildWindowProc" : "extDialogWindowProc"), + Father, pFatherProc); + pWindowProc = pFatherProc; + } + dxwws.PutProc(hwnd, pWindowProc); + if(dwStyle & WS_CHILD){ + OutTraceDW("%s: Hooking CHILD hwnd=%x father WindowProc %x->%x\n", ApiName, hwnd, pWindowProc, extChildWindowProc); + res=(*pSetWindowLongA)(hwnd, GWL_WNDPROC, (LONG)extChildWindowProc); + } + else { // must be dwStyle & WS_DLGFRAME + OutTraceDW("%s: Hooking DLGFRAME hwnd=%x father WindowProc %x->%x\n", ApiName, hwnd, pWindowProc, extDialogWindowProc); + res=(*pSetWindowLongA)(hwnd, GWL_WNDPROC, (LONG)extDialogWindowProc); + } + if(!res) OutTraceE("%s: SetWindowLong ERROR %x\n", ApiName, GetLastError()); +} + +HWND hControlParentWnd = NULL; + +// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms632679%28v=vs.85%29.aspx + +static BOOL IsFullscreenWindow( + void *lpClassName, + DWORD dwStyle, + DWORD dwExStyle, + HWND hWndParent, + int x, + int y, + int nWidth, + int nHeight) +{ + if (dwExStyle & WS_EX_CONTROLPARENT) return FALSE; // "Diablo" fix + if ((dwStyle & WS_CHILD) && (!dxw.IsDesktop(hWndParent))) return FALSE; // Diablo fix + // if maximized. + if(dwStyle & WS_MAXIMIZE) return TRUE; + // go through here only when WS_CHILD of desktop window + if((x == CW_USEDEFAULT) && (dwStyle & (WS_POPUP|WS_CHILD))) x = y = 0; + if(nWidth == CW_USEDEFAULT){ + if (dwStyle & (WS_POPUP|WS_CHILD)) nWidth = nHeight = 0; + else nWidth = dxw.GetScreenWidth() - x; + } + // msdn undocumented case: x,y=(-1000, CW_USEDEFAULT) w,h=(CW_USEDEFAULT,CW_USEDEFAULT) in "Imperialism" + if(nHeight == CW_USEDEFAULT){ + y = 0; + nHeight = dxw.GetScreenHeight(); + } + // if bigger than screen ... + if((x<=0)&& + (y<=0)&& + (nWidth>=(int)dxw.GetScreenWidth())&& + (nHeight>=(int)dxw.GetScreenHeight())) return TRUE; + return FALSE; +} + +static HWND WINAPI extCreateWindowCommon( + LPCTSTR ApiName, + BOOL WideChar, + DWORD dwExStyle, + void *lpClassName, + void *lpWindowName, + DWORD dwStyle, + int x, + int y, + int nWidth, + int nHeight, + HWND hWndParent, + HMENU hMenu, + HINSTANCE hInstance, + LPVOID lpParam) +{ + HWND hwnd; + BOOL isValidHandle=TRUE; + int iOrigW, iOrigH; + + iOrigW=nWidth; + iOrigH=nHeight; + if(!dxw.Windowize || (hWndParent == HWND_MESSAGE)){ // v2.02.87: don't process message windows (hWndParent == HWND_MESSAGE) + if(WideChar) + hwnd= (*pCreateWindowExW)(dwExStyle, (LPCWSTR)lpClassName, (LPCWSTR)lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + else + hwnd= (*pCreateWindowExA)(dwExStyle, (LPCSTR)lpClassName, (LPCSTR)lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + + if ((dxw.dwFlags1 & HOOKCHILDWIN) && (dwStyle & (WS_CHILD|WS_DLGFRAME))) + HookChildWndProc(hwnd, dwStyle, ApiName); + + OutTraceDW("%s: ret=%x\n", ApiName, hwnd); + return hwnd; + } + + // no maximized windows in any case + if (dxw.dwFlags1 & PREVENTMAXIMIZE){ + OutTraceDW("%s: handling PREVENTMAXIMIZE mode\n", ApiName); + dwStyle &= ~WS_MAXIMIZE; + } + + if(dxw.dwFlags6 & CREATEDESKTOP){ + extern HWND hDesktopWindow; + if (dxw.IsRealDesktop(hWndParent)){ + OutTraceE("%s: new parent win %x->%x\n", ApiName, hWndParent, hDesktopWindow); + hWndParent=hDesktopWindow; + } + } + + // v2.1.92: fixes size & position for auxiliary big window, often used + // for intro movies etc. : needed for ...... + // evidently, this was supposed to be a fullscreen window.... + // v2.1.100: fixes for "The Grinch": this game creates a new main window for OpenGL + // rendering using CW_USEDEFAULT placement and 800x600 size while the previous + // main win was 640x480 only! + // v2.02.13: if it's a WS_CHILD window, don't reposition the x,y, placement for BIG win. + // v2.02.30: fix (Fable - lost chapters) Fable creates a bigger win with negative x,y coordinates. + // v2.03.53: revised code, logic moved to IsFullscreenWindow + + if(IsFullscreenWindow(lpClassName, dwStyle, dwExStyle, hWndParent, x, y, nWidth, nHeight)){ + RECT screen; + POINT upleft = {0,0}; + + // update virtual screen size if it has grown + dxw.SetScreenSize(nWidth, nHeight); + + // inserted some checks here, since the main window could be destroyed + // or minimized (see "Jedi Outcast") so that you may get a dangerous + // zero size. In this case, better renew the hWnd assignement and its coordinates. + do { // fake loop + isValidHandle = FALSE; + if (!(*pGetClientRect)(dxw.GethWnd(),&screen)) break; + if (!(*pClientToScreen)(dxw.GethWnd(),&upleft)) break; + if (screen.right==0 || screen.bottom==0) break; + isValidHandle = TRUE; + } while(FALSE); + if (isValidHandle){ // use parent's coordinates + if (!(dwStyle & WS_CHILD)){ + x=upleft.x; + y=upleft.y; + } + nWidth=screen.right; + nHeight=screen.bottom; + OutTraceDW("%s: fixed BIG win pos=(%d,%d) size=(%d,%d)\n", ApiName, x, y, nWidth, nHeight); + } + else { + x=dxw.iPosX; + y=dxw.iPosY; + nWidth=dxw.iSizX; + nHeight=dxw.iSizY; + OutTraceDW("%s: renewed BIG win pos=(%d,%d) size=(%d,%d)\n", ApiName, x, y, nWidth, nHeight); + } + dxw.SetFullScreen(TRUE); + if(dxw.Coordinates==DXW_DESKTOP_WORKAREA){ + RECT workarea; + (*pSystemParametersInfoA)(SPI_GETWORKAREA, NULL, &workarea, 0); + x=0; + y=0; + nWidth=workarea.right; + nHeight=workarea.bottom; + dwStyle=0; + OutTraceDW("%s: WORKAREA win pos=(%d,%d) size=(%d,%d)\n", ApiName, x, y, nWidth, nHeight); + } + else if(dxw.Coordinates==DXW_DESKTOP_FULL){ + RECT workarea; + (*pGetClientRect)((*pGetDesktopWindow)(), &workarea); + x=0; + y=0; + nWidth=workarea.right; + nHeight=workarea.bottom; + dwStyle=0; + OutTraceDW("%s: FULLDESKTOP win pos=(%d,%d) size=(%d,%d)\n", ApiName, x, y, nWidth, nHeight); + } + } + + if(!dxw.IsFullScreen()){ // v2.1.63: needed for "Monster Truck Madness" + if(WideChar) + hwnd= (*pCreateWindowExW)(dwExStyle, (LPCWSTR)lpClassName, (LPCWSTR)lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + else + hwnd= (*pCreateWindowExA)(dwExStyle, (LPCSTR)lpClassName, (LPCSTR)lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + OutTraceDW("%s: windowed mode ret=%x\n", ApiName, hwnd); + return hwnd; + } + + // from here on, fullscreen is garanteed + + if (dwStyle & WS_CHILD){ + // tested on Gangsters: coordinates must be window-relative!!! + // Age of Empires.... + dxw.MapClient(&x, &y, &nWidth, &nHeight); + OutTraceDW("%s: fixed WS_CHILD pos=(%d,%d) size=(%d,%d)\n", + ApiName, x, y, nWidth, nHeight); + } + else { + if ((dwExStyle & WS_EX_CONTROLPARENT) || (dwStyle & WS_POPUP)){ + // needed for "Diablo", that creates a new WS_EX_CONTROLPARENT window that must be + // overlapped to the directdraw surface. + // needed for "Riven", that creates a new WS_POPUP window with the menu bar that must be + // overlapped to the directdraw surface. + dxw.MapWindow(&x, &y, &nWidth, &nHeight); + OutTraceDW("%s: fixed pos=(%d,%d) size=(%d,%d)\n", + ApiName, x, y, nWidth, nHeight); + } + } + + OutTraceB("%s: fixed pos=(%d,%d) size=(%d,%d) Style=%x(%s) ExStyle=%x(%s)\n", + ApiName, x, y, nWidth, nHeight, dwStyle, ExplainStyle(dwStyle), dwExStyle, ExplainExStyle(dwExStyle)); + + if(WideChar) + hwnd= (*pCreateWindowExW)(dwExStyle, (LPCWSTR)lpClassName, (LPCWSTR)lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + else + hwnd= (*pCreateWindowExA)(dwExStyle, (LPCSTR)lpClassName, (LPCSTR)lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + if (hwnd==(HWND)NULL){ + OutTraceE("%s: ERROR err=%d Style=%x(%s) ExStyle=%x\n", + ApiName, GetLastError(), dwStyle, ExplainStyle(dwStyle), dwExStyle); + return hwnd; + } + + if (dwExStyle & WS_EX_CONTROLPARENT) hControlParentWnd=hwnd; + + if ((!isValidHandle) && dxw.IsFullScreen()){ + dxw.SethWnd(hwnd); + extern void AdjustWindowPos(HWND, DWORD, DWORD); + (*pSetWindowLongA)(hwnd, GWL_STYLE, (dxw.dwFlags2 & MODALSTYLE) ? 0 : WS_OVERLAPPEDWINDOW); + (*pSetWindowLongA)(hwnd, GWL_EXSTYLE, 0); + OutTraceDW("%s: hwnd=%x, set style=WS_OVERLAPPEDWINDOW extstyle=0\n", ApiName, hwnd); + AdjustWindowPos(hwnd, nWidth, nHeight); + (*pShowWindow)(hwnd, SW_SHOWNORMAL); + } + + //if ((dxw.dwFlags1 & FIXWINFRAME) && !(dwStyle & WS_CHILD)) + if ((dxw.dwFlags1 & FIXWINFRAME) && !(dwStyle & WS_CHILD) && dxw.IsDesktop(hwnd)) + dxw.FixWindowFrame(hwnd); + + if ((dxw.dwFlags1 & HOOKCHILDWIN) && (dwStyle & (WS_CHILD|WS_DLGFRAME))) + HookChildWndProc(hwnd, dwStyle, ApiName); + + if ((FIXCHILDSIZE) && (dwStyle & (WS_CHILD|WS_DLGFRAME))) + dxwws.PutSize(hwnd, iOrigW, iOrigH); + + // "Hoyle Casino Empire" needs to be in a maximized state to continue after the intro movie. + // Sending a SW_MAXIMIZE message intercepted by the PREVENTMAXIMIZE handling fixes the problem. + //if (dxw.IsFullScreen() && (dxw.dwFlags1 & PREVENTMAXIMIZE)){ + if ((hwnd == dxw.GethWnd()) && dxw.IsFullScreen() && (dxw.dwFlags1 & PREVENTMAXIMIZE)){ + OutTraceDW("%s: entering maximized state\n", ApiName); + (*pShowWindow)(hwnd, SW_MAXIMIZE); + } + + if(dxw.dwFlags1 & CLIPCURSOR) dxw.SetClipCursor(); + + OutTraceDW("%s: ret=%x\n", ApiName, hwnd); + return hwnd; +} + +static LPCSTR ClassToStr(LPCSTR Class) +{ + static char AtomBuf[20+1]; + if(((DWORD)Class & 0xFFFF0000) == 0){ + sprintf(AtomBuf, "ATOM(%X)", (DWORD)Class); + return AtomBuf; + } + return Class; +} + +static LPCWSTR ClassToWStr(LPCWSTR Class) +{ + static WCHAR AtomBuf[20+1]; + if(((DWORD)Class & 0xFFFF0000) == 0){ + swprintf(AtomBuf, L"ATOM(%X)", (DWORD)Class); + return AtomBuf; + } + return Class; +} +// to do: implement and use ClassToWStr() for widechar call + +HWND WINAPI extCreateWindowExW( + DWORD dwExStyle, + LPCWSTR lpClassName, + LPCWSTR lpWindowName, + DWORD dwStyle, + int x, + int y, + int nWidth, + int nHeight, + HWND hWndParent, + HMENU hMenu, + HINSTANCE hInstance, + LPVOID lpParam) +{ + if(IsTraceDW){ + char xString[20], yString[20], wString[20], hString[20]; + if (x==CW_USEDEFAULT) strcpy(xString,"CW_USEDEFAULT"); + else sprintf(xString,"%d", x); + if (y==CW_USEDEFAULT) strcpy(yString,"CW_USEDEFAULT"); + else sprintf(yString,"%d", y); + if (nWidth==CW_USEDEFAULT) strcpy(wString,"CW_USEDEFAULT"); + else sprintf(wString,"%d", nWidth); + if (nHeight==CW_USEDEFAULT) strcpy(hString,"CW_USEDEFAULT"); + else sprintf(hString,"%d", nHeight); + OutTrace("CreateWindowExW: class=\"%ls\" wname=\"%ls\" pos=(%s,%s) size=(%s,%s) Style=%x(%s) ExStyle=%x(%s) hWndParent=%x%s hMenu=%x\n", + ClassToWStr(lpClassName), lpWindowName, xString, yString, wString, hString, + dwStyle, ExplainStyle(dwStyle), dwExStyle, ExplainExStyle(dwExStyle), + hWndParent, hWndParent==HWND_MESSAGE?"(HWND_MESSAGE)":"", hMenu); + } + OutTraceB("CreateWindowExW: DEBUG fullscreen=%x mainwin=%x screen=(%d,%d)\n", + dxw.IsFullScreen(), dxw.GethWnd(), dxw.GetScreenWidth(), dxw.GetScreenHeight()); + + if((dxw.dwFlags6 & STRETCHMOVIES) && !wcscmp(lpWindowName, L"ActiveMovie Window")){ + RECT MainWin; + (*pGetClientRect)(dxw.GethWnd(), &MainWin); + nWidth = MainWin.right; + nHeight = MainWin.bottom; + } + + return extCreateWindowCommon("CreateWindowExW", TRUE, dwExStyle, (void *)lpClassName, (void *)lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); +} + +// GHO: pro Diablo +HWND WINAPI extCreateWindowExA( + DWORD dwExStyle, + LPCTSTR lpClassName, + LPCTSTR lpWindowName, + DWORD dwStyle, + int x, + int y, + int nWidth, + int nHeight, + HWND hWndParent, + HMENU hMenu, + HINSTANCE hInstance, + LPVOID lpParam) +{ + if(IsTraceDW){ + char xString[20], yString[20], wString[20], hString[20]; + if (x==CW_USEDEFAULT) strcpy(xString,"CW_USEDEFAULT"); + else sprintf(xString,"%d", x); + if (y==CW_USEDEFAULT) strcpy(yString,"CW_USEDEFAULT"); + else sprintf(yString,"%d", y); + if (nWidth==CW_USEDEFAULT) strcpy(wString,"CW_USEDEFAULT"); + else sprintf(wString,"%d", nWidth); + if (nHeight==CW_USEDEFAULT) strcpy(hString,"CW_USEDEFAULT"); + else sprintf(hString,"%d", nHeight); + OutTrace("CreateWindowExA: class=\"%s\" wname=\"%s\" pos=(%s,%s) size=(%s,%s) Style=%x(%s) ExStyle=%x(%s) hWndParent=%x%s hMenu=%x\n", + ClassToStr(lpClassName), lpWindowName, xString, yString, wString, hString, + dwStyle, ExplainStyle(dwStyle), dwExStyle, ExplainExStyle(dwExStyle), + hWndParent, hWndParent==HWND_MESSAGE?"(HWND_MESSAGE)":"", hMenu); + } + OutTraceB("CreateWindowExA: DEBUG fullscreen=%x mainwin=%x screen=(%d,%d)\n", + dxw.IsFullScreen(), dxw.GethWnd(), dxw.GetScreenWidth(), dxw.GetScreenHeight()); + + if((dxw.dwFlags6 & STRETCHMOVIES) && !strcmp(lpWindowName, "ActiveMovie Window")){ + RECT MainWin; + (*pGetClientRect)(dxw.GethWnd(), &MainWin); + nWidth = MainWin.right; + nHeight = MainWin.bottom; + } + + return extCreateWindowCommon("CreateWindowExA", FALSE, dwExStyle, (void *)lpClassName, (void *)lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); +} + +LRESULT WINAPI extCallWindowProcA(WNDPROC lpPrevWndFunc, HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + // v2.02.30: fix (Imperialism II): apply to main window only !!! + HRESULT res; + + res = -1; + if(hwnd == dxw.GethWnd()) res=FixWindowProc("CallWindowProcA", hwnd, Msg, wParam, &lParam); + + if (res==(HRESULT)-1) + return (*pCallWindowProcA)(lpPrevWndFunc, hwnd, Msg, wParam, lParam); + else + return res; +} + +LRESULT WINAPI extCallWindowProcW(WNDPROC lpPrevWndFunc, HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + // v2.02.30: fix (Imperialism II): apply to main window only !!! + HRESULT res; + + res = -1; + if(hwnd == dxw.GethWnd()) res=FixWindowProc("CallWindowProcW", hwnd, Msg, wParam, &lParam); + + if (res==(HRESULT)-1) + return (*pCallWindowProcW)(lpPrevWndFunc, hwnd, Msg, wParam, lParam); + else + return res; +} + +LRESULT WINAPI extDefWindowProcA(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + // v2.02.30: fix (Imperialism II): apply to main window only !!! + // v2.03.50: fix - do clip cursor only after the window has got focus + HRESULT res; + res = (HRESULT)-1; + if(hwnd == dxw.GethWnd()) res=FixWindowProc("DefWindowProcA", hwnd, Msg, wParam, &lParam); + if (res==(HRESULT)-1) res = (*pDefWindowProcA)(hwnd, Msg, wParam, lParam); + if((Msg == WM_SETFOCUS) && (dxw.dwFlags1 & CLIPCURSOR)) dxw.SetClipCursor(); + return res; +} + +LRESULT WINAPI extDefWindowProcW(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + // v2.02.30: fix (Imperialism II): apply to main window only !!! + // v2.03.50: fix - do clip cursor only after the window has got focus + HRESULT res; + res = (HRESULT)-1; + if(hwnd == dxw.GethWnd()) res=FixWindowProc("DefWindowProcW", hwnd, Msg, wParam, &lParam); + if (res==(HRESULT)-1) res = (*pDefWindowProcW)(hwnd, Msg, wParam, lParam); + if((Msg == WM_SETFOCUS) && (dxw.dwFlags1 & CLIPCURSOR)) dxw.SetClipCursor(); + return res; +} + +static int HandleRect(char *ApiName, void *pFun, HDC hdc, const RECT *lprc, HBRUSH hbr) +{ + // used for both FillRect and FrameRect calls + int res; + RECT rc; + OutTraceDW("%s: hdc=%x hbrush=%x rect=(%d,%d)-(%d,%d)\n", ApiName, hdc, hbr, lprc->left, lprc->top, lprc->right, lprc->bottom); + + if(dxw.dwFlags4 & NOFILLRECT) { + OutTraceDW("%s: SUPPRESS\n", ApiName, hdc, hbr, lprc->left, lprc->top, lprc->right, lprc->bottom); + return TRUE; + } + + memcpy(&rc, lprc, sizeof(rc)); + + // Be careful: when you call CreateCompatibleDC with NULL DC, it is created a memory DC + // with same characteristics as desktop. That would return true from the call to + // dxw.IsRealDesktop(WindowFromDC(hdc)) because WindowFromDC(hdc) is null. + // So, it's fundamental to check also the hdc type (OBJ_DC is a window's DC) + + if((dxw.IsRealDesktop(WindowFromDC(hdc)) && (OBJ_DC == GetObjectType(hdc)))) { + HWND VirtualDesktop; + VirtualDesktop=dxw.GethWnd(); + if(VirtualDesktop==NULL){ + OutTraceDW("%s: no virtual desktop\n", ApiName); + return TRUE; + } + OutTraceDW("%s: remapped hdc to virtual desktop hwnd=%x\n", ApiName, dxw.GethWnd()); + hdc=(*pGDIGetDC)(dxw.GethWnd()); + } + + if(dxw.IsToRemap(hdc)) { + if(rc.left < 0) rc.left = 0; + if(rc.top < 0) rc.top = 0; + if((DWORD)rc.right > dxw.GetScreenWidth()) rc.right = dxw.GetScreenWidth(); + if((DWORD)rc.bottom > dxw.GetScreenHeight()) rc.bottom = dxw.GetScreenHeight(); + + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + if (sdc.GetPrimaryDC(hdc)){ + res=(*(FillRect_Type)pFun)(sdc.GetHdc(), &rc, hbr); + sdc.PutPrimaryDC(hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top); + return res; + } + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&rc); + OutTraceDW("%s: fixed rect=(%d,%d)-(%d,%d)\n", ApiName, rc.left, rc.top, rc.right, rc.bottom); + break; + default: + break; + } + } + else { + // when not in fullscreen mode, just proxy the call + // but check coordinates: some games may use excessive coordinates: see "Premier Manager 98" + RECT client; + HWND hwnd; + hwnd=WindowFromDC(hdc); + (*pGetClientRect)(hwnd, &client); + if(rc.left < 0) rc.left=0; + if(rc.top < 0) rc.top=0; + if(rc.right > client.right) rc.right=client.right; + if(rc.bottom > client.bottom) rc.bottom=client.bottom; + OutTraceDW("%s: remapped hdc from hwnd=%x to rect=(%d,%d)-(%d,%d)\n", ApiName, hwnd, rc.left, rc.top, rc.right, rc.bottom); + } + + res=(*(FillRect_Type)pFun)(hdc, &rc, hbr); + return res; +} + +int WINAPI extFillRect(HDC hdc, const RECT *lprc, HBRUSH hbr) +{ + return HandleRect("FillRect", (void *)pFillRect, hdc, lprc, hbr); +} + +int WINAPI extFrameRect(HDC hdc, const RECT *lprc, HBRUSH hbr) +{ + return HandleRect("FramelRect", (void *)pFrameRect, hdc, lprc, hbr); +} + +BOOL WINAPI extInvertRect(HDC hdc, const RECT *lprc) +{ + int res; + RECT rc; + OutTraceDW("InvertRect: hdc=%x rect=(%d,%d)-(%d,%d)\n", hdc, lprc->left, lprc->top, lprc->right, lprc->bottom); + + memcpy(&rc, lprc, sizeof(rc)); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + if(sdc.GetPrimaryDC(hdc)){ + res=(*pInvertRect)(sdc.GetHdc(), &rc); + sdc.PutPrimaryDC(hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top); + return res; + } + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&rc); + OutTraceDW("InvertRect: fixed rect=(%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom); + break; + default: + break; + } + } + + res=(*pInvertRect)(hdc, &rc); + return res; +} + +int WINAPI extValidateRect(HWND hwnd, const RECT *lprc) +{ + int res; + RECT rc; + + OutTraceDW("ValidateRect: hwnd=%x rect=(%d,%d)-(%d,%d)\n", + hwnd, lprc->left, lprc->top, lprc->right, lprc->bottom); + + memcpy(&rc, lprc, sizeof(rc)); + + if(dxw.IsFullScreen()) { + if(dxw.IsRealDesktop(hwnd)) hwnd=dxw.GethWnd(); + dxw.MapClient(&rc); + OutTraceDW("ValidateRect: fixed rect=(%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom); + } + + res=(*pValidateRect)(hwnd, &rc); + return res; +} + +BOOL WINAPI extClipCursor(RECT *lpRectArg) +{ + // reference: hooking and setting ClipCursor is mandatori in "Emergency: Fighters for Life" + // where the application expects the cursor to be moved just in a inner rect within the + // main window surface. + + BOOL res; + RECT *lpRect; + RECT Rect; + + if(IsTraceC){ + if (lpRectArg) + OutTrace("ClipCursor: rect=(%d,%d)-(%d,%d)\n", + lpRectArg->left,lpRectArg->top,lpRectArg->right,lpRectArg->bottom); + else + OutTrace("ClipCursor: rect=(NULL)\n"); + } + + if (!(dxw.dwFlags1 & ENABLECLIPPING)) return 1; + + if(lpRectArg){ + Rect=*lpRectArg; + lpRect=&Rect; + } + else + lpRect=NULL; + + if(dxw.dwFlags1 & MODIFYMOUSE){ + // save desired clip region + // v2.02.39: fix - do not attempt to write to NULL lpRect + if (lpRect) { + ClipRegion=*lpRectArg; + lpClipRegion=&ClipRegion; + *lpRect=dxw.MapWindowRect(lpRect); + } + else + lpClipRegion=NULL; + } + + if (pClipCursor) res=(*pClipCursor)(lpRect); + if (lpRect) OutTraceDW("ClipCursor: REMAPPED rect=(%d,%d)-(%d,%d) res=%x\n", lpRect->left,lpRect->top,lpRect->right,lpRect->bottom, res); + + return TRUE; +} + +BOOL WINAPI extGetClipCursor(LPRECT lpRect) +{ + // v2.1.93: if ENABLECLIPPING, return the saved clip rect coordinates + + BOOL ret; + + // proxy.... + if (!(dxw.dwFlags1 & ENABLECLIPPING)) { + ret=(*pGetClipCursor)(lpRect); + // v2.03.11: fix for "SubCulture" mouse movement + if(lpRect && dxw.Windowize) *lpRect = dxw.GetScreenRect(); + if(IsTraceDDRAW){ + if (lpRect) + OutTrace("GetClipCursor: rect=(%d,%d)-(%d,%d) ret=%d\n", + lpRect->left,lpRect->top,lpRect->right,lpRect->bottom, ret); + else + OutTrace("GetClipCursor: rect=(NULL) ret=%d\n", ret); + } + return ret; + } + + if(lpRect){ + if(lpClipRegion) + *lpRect=ClipRegion; + else + *lpRect=dxw.GetScreenRect(); + OutTraceDW("GetClipCursor: rect=(%d,%d)-(%d,%d) ret=%d\n", + lpRect->left,lpRect->top,lpRect->right,lpRect->bottom, TRUE); + } + + return TRUE; +} + +LONG WINAPI extEnumDisplaySettings(LPCTSTR lpszDeviceName, DWORD iModeNum, DEVMODE *lpDevMode) +{ + LONG res; + OSVERSIONINFO osinfo; + + osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + (*pGetVersionExA)(&osinfo); + OutTraceDW("EnumDisplaySettings: Devicename=%s ModeNum=%x OS=%d.%d\n", lpszDeviceName, iModeNum, osinfo.dwMajorVersion, osinfo.dwMinorVersion); + + if(dxw.dwFlags4 & NATIVERES){ + // lists video card native resolutions, though faking emulated color resolutions + if((osinfo.dwMajorVersion >= 6) && (dxw.dwFlags1 & EMULATESURFACE)){ + switch(iModeNum){ + case ENUM_CURRENT_SETTINGS: + case ENUM_REGISTRY_SETTINGS: // lie ... + res=(*pEnumDisplaySettings)(lpszDeviceName, iModeNum, lpDevMode); + if(dxw.dwFlags2 & INIT8BPP) lpDevMode->dmBitsPerPel = 8; + if(dxw.dwFlags2 & INIT16BPP) lpDevMode->dmBitsPerPel = 16; + if(dxw.dwFlags3 & FORCE16BPP) lpDevMode->dmBitsPerPel = 16; + break; + default: + res=(*pEnumDisplaySettings)(lpszDeviceName, iModeNum / SUPPORTED_DEPTHS_NUMBER, lpDevMode); + lpDevMode->dmBitsPerPel = (DWORD)SupportedDepths[iModeNum % SUPPORTED_DEPTHS_NUMBER]; + break; + } + } + else + res=(*pEnumDisplaySettings)(lpszDeviceName, iModeNum, lpDevMode); + + } + else { // simulated modes: VGA or HDTV + //int SupportedDepths[5]={8,16,24,32,0}; + SupportedRes_Type *SupportedRes; + SupportedRes = (dxw.dwFlags4 & SUPPORTHDTV) ? &SupportedHDTVRes[0] : &SupportedSVGARes[0]; + res=(*pEnumDisplaySettings)(lpszDeviceName, ENUM_CURRENT_SETTINGS, lpDevMode); + switch(iModeNum){ + case ENUM_CURRENT_SETTINGS: + case ENUM_REGISTRY_SETTINGS: // lie ... + lpDevMode->dmPelsHeight = 600; + lpDevMode->dmPelsWidth = 800; + if(dxw.dwFlags2 & INIT8BPP) lpDevMode->dmBitsPerPel = 8; + if(dxw.dwFlags2 & INIT16BPP) lpDevMode->dmBitsPerPel = 16; + if(dxw.dwFlags3 & FORCE16BPP) lpDevMode->dmBitsPerPel = 16; + break; + default: + lpDevMode->dmPelsHeight = SupportedRes[iModeNum / 4].h; + lpDevMode->dmPelsWidth = SupportedRes[iModeNum / 4].w; + lpDevMode->dmBitsPerPel = SupportedDepths[iModeNum % 4]; + if(lpDevMode->dmPelsHeight == 0) res = 0; // end of list + break; + } + } + + if(dxw.dwFlags4 & LIMITSCREENRES){ + #define HUGE 100000 + DWORD maxw, maxh; + maxw = maxh = HUGE; + switch(dxw.MaxScreenRes){ + case DXW_NO_LIMIT: maxw=HUGE; maxh=HUGE; break; + case DXW_LIMIT_320x200: maxw=320; maxh=200; break; + case DXW_LIMIT_640x480: maxw=640; maxh=480; break; + case DXW_LIMIT_800x600: maxw=800; maxh=600; break; + case DXW_LIMIT_1024x768: maxw=1024; maxh=768; break; + case DXW_LIMIT_1280x960: maxw=1280; maxh=960; break; + } + if((lpDevMode->dmPelsWidth > maxw) || (lpDevMode->dmPelsHeight > maxh)){ + OutTraceDW("EnumDisplaySettings: limit device size=(%d,%d)\n", maxw, maxh); + lpDevMode->dmPelsWidth = maxw; + lpDevMode->dmPelsHeight = maxh; + } + } + + OutTraceDW("EnumDisplaySettings: color=%dBPP size=(%dx%d) refresh=%dHz\n", + lpDevMode->dmBitsPerPel, lpDevMode->dmPelsWidth, lpDevMode->dmPelsHeight, lpDevMode->dmDisplayFrequency); + return res; +} + +LONG WINAPI extChangeDisplaySettingsA(DEVMODEA *lpDevMode, DWORD dwflags) +{ + if(IsTraceDDRAW){ + char sInfo[1024]; + strcpy(sInfo, ""); + if (lpDevMode) sprintf(sInfo, " DeviceName=%s fields=%x(%s) size=(%d x %d) bpp=%d", + lpDevMode->dmDeviceName, lpDevMode->dmFields, ExplainDevModeFields(lpDevMode->dmFields), + lpDevMode->dmPelsWidth, lpDevMode->dmPelsHeight, lpDevMode->dmBitsPerPel); + OutTrace("ChangeDisplaySettingsA: lpDevMode=%x flags=%x(%s)%s\n", + lpDevMode, dwflags, ExplainChangeDisplaySettingsFlags(dwflags), sInfo); + } + + if(dxw.Windowize) + return MyChangeDisplaySettings("ChangeDisplaySettingsA", FALSE, lpDevMode, dwflags); + else + return (*pChangeDisplaySettingsExA)(NULL, lpDevMode, NULL, dwflags, NULL); +} + +LONG WINAPI extChangeDisplaySettingsW(DEVMODEW *lpDevMode, DWORD dwflags) +{ + if(IsTraceDDRAW){ + char sInfo[1024]; + strcpy(sInfo, ""); + if (lpDevMode) sprintf(sInfo, " DeviceName=%ls fields=%x(%s) size=(%d x %d) bpp=%d", + lpDevMode->dmDeviceName, lpDevMode->dmFields, ExplainDevModeFields(lpDevMode->dmFields), + lpDevMode->dmPelsWidth, lpDevMode->dmPelsHeight, lpDevMode->dmBitsPerPel); + OutTrace("ChangeDisplaySettingsW: lpDevMode=%x flags=%x(%s)%s\n", + lpDevMode, dwflags, ExplainChangeDisplaySettingsFlags(dwflags), sInfo); + } + + if(dxw.Windowize) + return MyChangeDisplaySettings("ChangeDisplaySettingsW", TRUE, lpDevMode, dwflags); + else + return (*pChangeDisplaySettingsW)(lpDevMode, dwflags); +} + +LONG WINAPI extChangeDisplaySettingsExA(LPCTSTR lpszDeviceName, DEVMODEA *lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) +{ + if(IsTraceDDRAW){ + char sInfo[1024]; + strcpy(sInfo, ""); + if (lpDevMode) sprintf(sInfo, " DeviceName=%s fields=%x(%s) size=(%d x %d) bpp=%d", + lpDevMode->dmDeviceName, lpDevMode->dmFields, ExplainDevModeFields(lpDevMode->dmFields), + lpDevMode->dmPelsWidth, lpDevMode->dmPelsHeight, lpDevMode->dmBitsPerPel); + OutTrace("ChangeDisplaySettingsExA: DeviceName=%s lpDevMode=%x flags=%x(%s)%s\n", + lpszDeviceName, lpDevMode, dwflags, ExplainChangeDisplaySettingsFlags(dwflags), sInfo); + } + + if(dxw.Windowize) + return MyChangeDisplaySettings("ChangeDisplaySettingsExA", FALSE, lpDevMode, dwflags); + else + return (*pChangeDisplaySettingsExA)(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); +} + +LONG WINAPI extChangeDisplaySettingsExW(LPCTSTR lpszDeviceName, DEVMODEW *lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) +{ + if(IsTraceDDRAW){ + char sInfo[1024]; + strcpy(sInfo, ""); + if (lpDevMode) sprintf(sInfo, " DeviceName=%ls fields=%x(%s) size=(%d x %d) bpp=%d", + lpDevMode->dmDeviceName, lpDevMode->dmFields, ExplainDevModeFields(lpDevMode->dmFields), + lpDevMode->dmPelsWidth, lpDevMode->dmPelsHeight, lpDevMode->dmBitsPerPel); + OutTrace("ChangeDisplaySettingsExW: DeviceName=%ls lpDevMode=%x flags=%x(%s)%s\n", + lpszDeviceName, lpDevMode, dwflags, ExplainChangeDisplaySettingsFlags(dwflags), sInfo); + } + + if(dxw.Windowize) + return MyChangeDisplaySettings("ChangeDisplaySettingsExW", TRUE, lpDevMode, dwflags); + else + return (*pChangeDisplaySettingsExW)(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); +} + +static HDC WINAPI sGetDC(HWND hwnd, char *ApiName) +{ + // to do: add parameter and reference to pGDIGetDCEx to merge properly GetDC and GetDCEx + HDC ret; + HWND lochwnd; + + if(!dxw.IsFullScreen() || (dxw.dwFlags6 & SHAREDDC)) return(*pGDIGetDC)(hwnd); + + lochwnd=hwnd; + + if (dxw.IsRealDesktop(hwnd)) { + OutTraceDW("%s: desktop remapping hwnd=%x->%x\n", ApiName, hwnd, dxw.GethWnd()); + lochwnd=dxw.GethWnd(); + } + + //if(bFlippedDC) { + // ret = dxw.AcquireSharedDC(hwnd); + // if(ret) return ret; + //} + + switch(dxw.GDIEmulationMode){ + case GDIMODE_STRETCHED: + ret=(*pGDIGetDC)(lochwnd); + break; + case GDIMODE_EMULATED: + ret=dxw.AcquireEmulatedDC(lochwnd); + break; + } + + if(ret){ + OutTraceDW("%s: hwnd=%x ret=%x\n", ApiName, lochwnd, ret); + } + else{ + int err; + err=GetLastError(); + OutTraceE("%s ERROR: hwnd=%x err=%d at %d\n", ApiName, lochwnd, err, __LINE__); + if((err==ERROR_INVALID_WINDOW_HANDLE) && (lochwnd!=hwnd)){ + ret=(*pGDIGetDC)(hwnd); + if(ret) + OutTraceDW("%s: hwnd=%x ret=%x\n", ApiName, hwnd, ret); + else + OutTraceE("%s ERROR: hwnd=%x err=%d at %d\n", ApiName, hwnd, GetLastError(), __LINE__); + } + } + + return ret; +} + +HDC WINAPI extGDIGetDC(HWND hwnd) +{ + OutTraceDW("GDI.GetDC: hwnd=%x\n", hwnd); + return sGetDC(hwnd, "GDI.GetDC"); +} + +HDC WINAPI extGDIGetDCEx(HWND hwnd, HRGN hrgnClip, DWORD flags) +{ + // used by Star Wars Shadow of the Empire + OutTraceDW("GDI.GetDCEx: hwnd=%x hrgnClip=%x flags=%x(%s)\n", hwnd, hrgnClip, flags, ExplainGetDCExFlags(flags)); + return sGetDC(hwnd, "GDI.GetDCEx"); +} + +HDC WINAPI extGDIGetWindowDC(HWND hwnd) +{ + OutTraceDW("GDI.GetWindowDC: hwnd=%x\n", hwnd); + + // if not fullscreen or not desktop win, just proxy the call + if(!dxw.IsFullScreen() || !dxw.IsDesktop(hwnd)){ + HDC ret; + ret=(*pGDIGetWindowDC)(hwnd); + OutTraceDW("GDI.GetWindowDC: hwnd=%x hdc=%x\n", hwnd, ret); + return ret; + } + + return sGetDC(hwnd, "GDI.GetWindowDC"); +} + +int WINAPI extGDIReleaseDC(HWND hwnd, HDC hDC) +{ + int res; + + OutTraceDW("GDI.ReleaseDC: hwnd=%x hdc=%x\n", hwnd, hDC); + + if (dxw.IsRealDesktop(hwnd)) hwnd=dxw.GethWnd(); + if(hwnd == 0) return(TRUE); + + switch(dxw.GDIEmulationMode){ + case GDIMODE_STRETCHED: + res=(*pGDIReleaseDC)(hwnd, hDC); + break; + case GDIMODE_EMULATED: + res=dxw.ReleaseEmulatedDC(hwnd); + break; + } + + if (!res) OutTraceE("GDI.ReleaseDC ERROR: err=%d at %d\n", GetLastError(), __LINE__); + return(res); +} + +HDC WINAPI extBeginPaint(HWND hwnd, LPPAINTSTRUCT lpPaint) +{ + HDC hdc; + + OutTraceDW("GDI.BeginPaint: hwnd=%x lpPaint=%x FullScreen=%x\n", hwnd, lpPaint, dxw.IsFullScreen()); + + // avoid access to real desktop + if(dxw.IsRealDesktop(hwnd)) hwnd=dxw.GethWnd(); + + hdc=(*pBeginPaint)(hwnd, lpPaint); + + // if not in fullscreen mode, that's all! + if(!dxw.IsFullScreen()) return hdc; + + switch(dxw.GDIEmulationMode){ + case GDIMODE_STRETCHED: + // on CLIENTREMAPPING, resize the paint area to virtual screen size + //if(dxw.dwFlags1 & CLIENTREMAPPING) lpPaint->rcPaint=dxw.GetScreenRect(); + if(dxw.dwFlags1 & CLIENTREMAPPING) dxw.UnmapClient(&(lpPaint->rcPaint)); + break; + case GDIMODE_EMULATED: + HDC EmuHDC; + EmuHDC = dxw.AcquireEmulatedDC(hwnd); + lpPaint->hdc=EmuHDC; + hdc = EmuHDC; + break; + } + + + OutTraceDW("GDI.BeginPaint: hdc=%x rcPaint=(%d,%d)-(%d,%d)\n", + hdc, lpPaint->rcPaint.left, lpPaint->rcPaint.top, lpPaint->rcPaint.right, lpPaint->rcPaint.bottom); + return hdc; +} + +BOOL WINAPI extEndPaint(HWND hwnd, const PAINTSTRUCT *lpPaint) +{ + BOOL ret; + + OutTraceDW("GDI.EndPaint: hwnd=%x lpPaint=%x lpPaint.hdc=%x lpPaint.rcpaint=(%d,%d)-(%d-%d)\n", + hwnd, lpPaint, lpPaint->hdc, lpPaint->rcPaint.left, lpPaint->rcPaint.top, lpPaint->rcPaint.right, lpPaint->rcPaint.bottom); + + // if not fullscreen or not desktop win, just proxy the call + if(!dxw.IsFullScreen() || (dxw.dwFlags6 & SHAREDDC)){ + ret=(*pEndPaint)(hwnd, lpPaint); + return ret; + } + + // avoid access to real desktop + if(dxw.IsRealDesktop(hwnd)) hwnd=dxw.GethWnd(); + + switch(dxw.GDIEmulationMode){ + case GDIMODE_EMULATED: + ret=dxw.ReleaseEmulatedDC(hwnd); + break; + default: + ret=(*pEndPaint)(hwnd, lpPaint); + break; + } + + if(ret){ + OutTraceDW("GDI.EndPaint: hwnd=%x ret=%x\n", hwnd, ret); + } + else{ + OutTraceE("GDI.EndPaint ERROR: err=%d at %d\n", GetLastError(), __LINE__); + } + + return ret; +} + +HWND WINAPI extCreateDialogIndirectParam(HINSTANCE hInstance, LPCDLGTEMPLATE lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM lParamInit) +{ + HWND RetHWND; + BOOL FullScreen; + FullScreen = dxw.IsFullScreen(); + OutTraceDW("CreateDialogIndirectParam: hInstance=%x lpTemplate=(style=%x extstyle=%x items=%d pos=(%d,%d) size=(%dx%d)) hWndParent=%x lpDialogFunc=%x lParamInit=%x\n", + hInstance, + lpTemplate->style, lpTemplate->dwExtendedStyle, lpTemplate->cdit, lpTemplate->x, lpTemplate->y, lpTemplate->cx, lpTemplate->cy, + hWndParent, lpDialogFunc, lParamInit); + if(dxw.IsFullScreen() && hWndParent==NULL) hWndParent=dxw.GethWnd(); + dxw.SetFullScreen(FALSE); + RetHWND=(*pCreateDialogIndirectParam)(hInstance, lpTemplate, hWndParent, lpDialogFunc, lParamInit); + dxw.SetFullScreen(FullScreen); + + // v2.02.73: redirect lpDialogFunc only when it is nor NULL + if( lpDialogFunc && + !(dxw.dwFlags6 & NOWINDOWHOOKS)){ // v2.03.41 - debug option + dxwws.PutProc(RetHWND, (WNDPROC)lpDialogFunc); + if(!(*pSetWindowLongA)(RetHWND, DWL_DLGPROC, (LONG)extDialogWindowProc)) + OutTraceE("SetWindowLong: ERROR err=%d at %d\n", GetLastError(), __LINE__); + } + + OutTraceDW("CreateDialogIndirectParam: hwnd=%x\n", RetHWND); + return RetHWND; +} + +HWND WINAPI extCreateDialogParam(HINSTANCE hInstance, LPCTSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM lParamInit) +{ + HWND RetHWND; + BOOL FullScreen; + FullScreen = dxw.IsFullScreen(); + OutTraceDW("CreateDialogParam: hInstance=%x lpTemplateName=%s hWndParent=%x lpDialogFunc=%x lParamInit=%x\n", + hInstance, sTemplateName(lpTemplateName), hWndParent, lpDialogFunc, lParamInit); + if(hWndParent==NULL) hWndParent=dxw.GethWnd(); + dxw.SetFullScreen(FALSE); + RetHWND=(*pCreateDialogParam)(hInstance, lpTemplateName, hWndParent, lpDialogFunc, lParamInit); + dxw.SetFullScreen(FullScreen); + + // v2.02.73: redirect lpDialogFunc only when it is nor NULL: fix for "LEGO Stunt Rally" + if( lpDialogFunc && + !(dxw.dwFlags6 & NOWINDOWHOOKS)){ // v2.03.41 - debug option + dxwws.PutProc(RetHWND, (WNDPROC)lpDialogFunc); + if(!(*pSetWindowLongA)(RetHWND, DWL_DLGPROC, (LONG)extDialogWindowProc)) + OutTraceE("SetWindowLong: ERROR err=%d at %d\n", GetLastError(), __LINE__); + } + + OutTraceDW("CreateDialogParam: hwnd=%x\n", RetHWND); + return RetHWND; +} + +BOOL WINAPI extMoveWindow(HWND hwnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint) +{ + BOOL ret; + OutTraceDW("MoveWindow: hwnd=%x xy=(%d,%d) size=(%d,%d) repaint=%x fullscreen=%x\n", + hwnd, X, Y, nWidth, nHeight, bRepaint, dxw.IsFullScreen()); + + if(dxw.Windowize){ + if(dxw.IsDesktop(hwnd)){ + // v2.1.93: happens in "Emergency Fighters for Life" ... + // what is the meaning of this? is it related to video stretching? + OutTraceDW("MoveWindow: prevent moving desktop win\n"); + return TRUE; + } + + if((hwnd==dxw.GethWnd()) || (hwnd==dxw.hParentWnd)){ + OutTraceDW("MoveWindow: prevent moving main win\n"); + return TRUE; + } + + if (dxw.IsFullScreen() && (dxw.dwFlags1 & CLIENTREMAPPING)){ + POINT upleft={0,0}; + RECT client; + BOOL isChild; + (*pClientToScreen)(dxw.GethWnd(),&upleft); + (*pGetClientRect)(dxw.GethWnd(),&client); + if ((*pGetWindowLongA)(hwnd, GWL_STYLE) & WS_CHILD){ + isChild=TRUE; + // child coordinate adjustement + X = (X * client.right) / dxw.GetScreenWidth(); + Y = (Y * client.bottom) / dxw.GetScreenHeight(); + nWidth = (nWidth * client.right) / dxw.GetScreenWidth(); + nHeight = (nHeight * client.bottom) / dxw.GetScreenHeight(); + } + else { + isChild=FALSE; + // regular win coordinate adjustement + X = upleft.x + (X * client.right) / dxw.GetScreenWidth(); + Y = upleft.y + (Y * client.bottom) / dxw.GetScreenHeight(); + nWidth = (nWidth * client.right) / dxw.GetScreenWidth(); + nHeight = (nHeight * client.bottom) / dxw.GetScreenHeight(); + } + OutTraceDW("MoveWindow: DEBUG client=(%d,%d) screen=(%d,%d)\n", + client.right, client.bottom, dxw.GetScreenWidth(), dxw.GetScreenHeight()); + OutTraceDW("MoveWindow: hwnd=%x child=%x relocated to xy=(%d,%d) size=(%d,%d)\n", + hwnd, isChild, X, Y, nWidth, nHeight); + } + else{ + if((X==0)&&(Y==0)&&(nWidth==dxw.GetScreenWidth())&&(nHeight==dxw.GetScreenHeight())){ + // evidently, this was supposed to be a fullscreen window.... + RECT screen; + DWORD dwStyle; + POINT upleft = {0,0}; + (*pGetClientRect)(dxw.GethWnd(),&screen); + (*pClientToScreen)(dxw.GethWnd(),&upleft); + if((dwStyle=(*pGetWindowLongA)(hwnd, GWL_STYLE)) && WS_CHILDWINDOW){ + // Big main child window: see "Reah" + X=Y=0; + } + else{ + // Regular big main window, usual case. + X=upleft.x; + Y=upleft.y; + } + nWidth=screen.right; + nHeight=screen.bottom; + OutTraceDW("MoveWindow: fixed BIG win pos=(%d,%d) size=(%d,%d)\n", X, Y, nWidth, nHeight); + } + } + } + + ret=(*pMoveWindow)(hwnd, X, Y, nWidth, nHeight, bRepaint); + if(!ret) OutTraceE("MoveWindow: ERROR err=%d at %d\n", GetLastError(), __LINE__); + return ret; +} + +int WINAPI extShowCursor(BOOL bShow) +{ + static int iFakeCounter; + int ret; + + OutTraceC("ShowCursor: bShow=%x\n", bShow); + if (bShow){ + if (dxw.dwFlags1 & HIDEHWCURSOR){ + iFakeCounter++; + OutTraceC("ShowCursor: HIDEHWCURSOR ret=%x\n", iFakeCounter); + return iFakeCounter; + } + } + else { + if (dxw.dwFlags2 & SHOWHWCURSOR){ + iFakeCounter--; + OutTraceC("ShowCursor: SHOWHWCURSOR ret=%x\n", iFakeCounter); + return iFakeCounter; + } + } + ret=(*pShowCursor)(bShow); + OutTraceC("ShowCursor: ret=%x\n", ret); + return ret; +} + +BOOL WINAPI extDrawFocusRect(HDC hDC, const RECT *lprc) +{ + return TRUE; +} + +BOOL WINAPI extScrollDC(HDC hDC, int dx, int dy, const RECT *lprcScroll, const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate) +{ + MessageBox(0, "ScrollDC", "to do", MB_OK); + return TRUE; +} + +HWND WINAPI extGetTopWindow(HWND hwnd) +{ + HWND ret; + OutTraceDW("GetTopWindow: hwnd=%x fullscreen=%x\n", hwnd, dxw.IsFullScreen()); + // a fullscreen program is supposed to be always top Z-order on the desktop! + ret = (dxw.IsFullScreen() && dxw.IsDesktop(hwnd)) ? dxw.GethWnd() : (*pGetTopWindow)(hwnd); + OutTraceDW("GetTopWindow: ret=%x\n", ret); + return ret; +} + +LONG WINAPI extTabbedTextOutA(HDC hdc, int X, int Y, LPCTSTR lpString, int nCount, int nTabPositions, const LPINT lpnTabStopPositions, int nTabOrigin) +{ + BOOL res; + OutTraceDW("TabbedTextOut: hdc=%x xy=(%d,%d) nCount=%d nTP=%d nTOS=%d str=(%d)\"%s\"\n", + hdc, X, Y, nCount, nTabPositions, nTabOrigin, lpString); + + if(dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + if(sdc.GetPrimaryDC(hdc)){ + res=(*pTabbedTextOutA)(sdc.GetHdc(), X, Y, lpString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin); + sdc.PutPrimaryDC(hdc); + return res; + } + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&X, &Y); + break; + case GDIMODE_EMULATED: + if(dxw.IsVirtual(hdc)){ + X+=dxw.VirtualOffsetX; + Y+=dxw.VirtualOffsetY; + } + break; + default: + break; + } + OutTraceDW("TextOut: fixed dest=(%d,%d)\n", X, Y); + } + + res=(*pTabbedTextOutA)(hdc, X, Y, lpString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin); + return res; +} + +BOOL WINAPI extDestroyWindow(HWND hWnd) +{ + // v2.02.43: "Empire Earth" builds test surfaces that must be destroyed! + // v2.03.20: "Prince of Persia 3D" destroys the main window that must be preserved! + BOOL res; + OutTraceB("DestroyWindow: hwnd=%x\n", hWnd); + if (hWnd == dxw.GethWnd()) { + if(dxw.dwFlags6 & NODESTROYWINDOW) { + OutTraceDW("DestroyWindow: do NOT destroy main hwnd=%x\n", hWnd); + return TRUE; + } + OutTraceDW("DestroyWindow: destroy main hwnd=%x\n", hWnd); + dxw.SethWnd(NULL); + } + if (hControlParentWnd && (hWnd == hControlParentWnd)) { + OutTraceDW("DestroyWindow: destroy control parent hwnd=%x\n", hWnd); + hControlParentWnd = NULL; + } + res=(*pDestroyWindow)(hWnd); + if(!res)OutTraceE("DestroyWindow: ERROR err=%d\n", GetLastError()); + return res; +} + +static char *ExplainTAAlign(UINT c) +{ + static char eb[256]; + unsigned int l; + strcpy(eb,"TA_"); + strcat(eb, (c & TA_UPDATECP) ? "UPDATECP+" : "NOUPDATECP+"); + strcat(eb, (c & TA_RIGHT) ? (((c & TA_CENTER) == TA_CENTER) ? "CENTER+" : "RIGHT+") : "LEFT+"); + strcat(eb, (c & TA_BOTTOM) ? "BOTTOM+" : "TOP+"); + if ((c & TA_BASELINE)==TA_BASELINE) strcat(eb, "BASELINE+"); + if (c & TA_RTLREADING) strcat(eb, "RTLREADING+"); + l=strlen(eb); + eb[l-1]=0; + return(eb); +} + +static char *ExplainDTFormat(UINT c) +{ + static char eb[256]; + unsigned int l; + strcpy(eb,"DT_"); + if(!(c & (DT_CENTER|DT_RIGHT))) strcat(eb, "LEFT+"); + if(c & DT_CENTER) strcat(eb, "CENTER+"); + if(c & DT_RIGHT) strcat(eb, "RIGHT+"); + if(!(c & (DT_VCENTER|DT_BOTTOM))) strcat(eb, "TOP+"); + if(c & DT_VCENTER) strcat(eb, "VCENTER+"); + if(c & DT_BOTTOM) strcat(eb, "BOTTOM+"); + if(c & DT_WORDBREAK) strcat(eb, "WORDBREAK+"); + if(c & DT_SINGLELINE) strcat(eb, "SINGLELINE+"); + if(c & DT_EXPANDTABS) strcat(eb, "EXPANDTABS+"); + if(c & DT_TABSTOP) strcat(eb, "TABSTOP+"); + if(c & DT_NOCLIP) strcat(eb, "NOCLIP+"); + if(c & DT_EXTERNALLEADING) strcat(eb, "EXTERNALLEADING+"); + if(c & DT_CALCRECT) strcat(eb, "CALCRECT+"); + if(c & DT_NOPREFIX) strcat(eb, "NOPREFIX+"); + if(c & DT_INTERNAL) strcat(eb, "INTERNAL+"); + l=strlen(eb); + eb[l-1]=0; + return(eb); +} + +BOOL gFixed; + +int WINAPI extDrawTextA(HDC hdc, LPCTSTR lpchText, int nCount, LPRECT lpRect, UINT uFormat) +{ + int ret; + OutTraceDW("DrawText: hdc=%x rect=(%d,%d)-(%d,%d) Format=%x(%s) Text=(%d)\"%s\"\n", + hdc, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, uFormat, ExplainDTFormat(uFormat), nCount, lpchText); + + gFixed = TRUE; // semaphore to avoid multiple scaling with HOT patching + if(dxw.IsToRemap(hdc)){ + + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + if(sdc.GetPrimaryDC(hdc)){ + ret=(*pDrawText)(sdc.GetHdc(), lpchText, nCount, lpRect, uFormat); + sdc.PutPrimaryDC(hdc, lpRect->left, lpRect->top, lpRect->right-lpRect->left, lpRect->bottom-lpRect->top); + return ret; + } + break; + case GDIMODE_STRETCHED: + dxw.MapClient((RECT *)lpRect); + OutTraceDW("DrawText: fixed rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + ret=(*pDrawText)(hdc, lpchText, nCount, lpRect, uFormat); + dxw.UnmapClient((RECT *)lpRect); + OutTraceDW("DrawText: fixed output rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + break; + default: + ret=(*pDrawText)(hdc, lpchText, nCount, lpRect, uFormat); + break; + } + } + else { + ret=(*pDrawText)(hdc, lpchText, nCount, lpRect, uFormat); + } + gFixed = FALSE; + + // if nCount is zero, DrawRect returns 0 as text heigth, but this is not an error! (ref. "Imperialism II") + if(nCount && !ret) OutTraceE("DrawText: ERROR ret=%x err=%d\n", ret, GetLastError()); + return ret; +} + +int WINAPI extDrawTextExA(HDC hdc, LPTSTR lpchText, int nCount, LPRECT lpRect, UINT dwDTFormat, LPDRAWTEXTPARAMS lpDTParams) +{ + int ret; + OutTraceDW("DrawTextEx: hdc=%x rect=(%d,%d)-(%d,%d) DTFormat=%x Text=(%d)\"%s\"\n", + hdc, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, dwDTFormat, nCount, lpchText); + if (IsDebug){ + if(lpDTParams) + OutTrace("DTParams: size=%d (L,R)margins=(%d,%d) TabLength=%d lDrawn=%d\n", + lpDTParams->cbSize, lpDTParams->iLeftMargin, lpDTParams->iRightMargin, + lpDTParams->iTabLength, lpDTParams->uiLengthDrawn); + else + OutTrace("DTParams: NULL\n"); + } + + gFixed = TRUE; // semaphore to avoid multiple scaling with HOT patching + if(dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + if(sdc.GetPrimaryDC(hdc)){ + ret=(*pDrawTextEx)(sdc.GetHdc(), lpchText, nCount, lpRect, dwDTFormat, lpDTParams); + sdc.PutPrimaryDC(hdc, lpRect->left, lpRect->top, lpRect->right-lpRect->left, lpRect->bottom-lpRect->top); + return ret; + } + break; + case GDIMODE_STRETCHED: + dxw.MapClient((RECT *)lpRect); + OutTraceDW("DrawText: fixed rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + ret=(*pDrawTextEx)(hdc, lpchText, nCount, lpRect, dwDTFormat, lpDTParams); + dxw.UnmapClient((RECT *)lpRect); + OutTraceDW("DrawText: fixed output rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + break; + default: + ret=(*pDrawTextEx)(hdc, lpchText, nCount, lpRect, dwDTFormat, lpDTParams); + break; + } + } + else { + ret=(*pDrawTextEx)(hdc, lpchText, nCount, lpRect, dwDTFormat, lpDTParams); + } + gFixed = FALSE; + + // if nCount is zero, DrawRect returns 0 as text heigth, but this is not an error! (ref. "Imperialism II") + if(nCount && !ret) OutTraceE("DrawText: ERROR ret=%x err=%d\n", ret, GetLastError()); + return ret; +} + +BOOL WINAPI extCloseWindow(HWND hWnd) +{ + // from MSDN: Minimizes (but does not destroy) the specified window. + BOOL res; + OutTraceB("CloseWindow: hwnd=%x\n", hWnd); + if (hWnd == dxw.GethWnd()) { + OutTraceDW("CloseWindow: close main hwnd=%x\n", hWnd); + // do not delete the reference to main hWnd. + } + res=(*pCloseWindow)(hWnd); + if(!res)OutTraceE("CloseWindow: ERROR err=%d\n", GetLastError()); + return res; +} + +BOOL WINAPI extSetSysColors(int cElements, const INT *lpaElements, const COLORREF *lpaRgbValues) +{ + // v2.02.32: added to avoid SysColors changes by "Western Front" + BOOL ret; + OutTraceDW("SetSysColors: Elements=%d\n", cElements); + + if(dxw.dwFlags3 & LOCKSYSCOLORS) return TRUE; + + ret=(*pSetSysColors)(cElements, lpaElements, lpaRgbValues); + if(!ret) OutTraceE("SetSysColors: ERROR er=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extUpdateWindow(HWND hwnd) +{ + BOOL ret; + OutTraceDW("UpdateWindow: hwnd=%x\n", hwnd); + + if(dxw.Windowize && dxw.IsRealDesktop(hwnd)){ + OutTraceDW("UpdateWindow: remapping hwnd=%x->%x\n", hwnd, dxw.GethWnd()); + hwnd=dxw.GethWnd(); + } + + ret=(*pUpdateWindow)(hwnd); + if(!ret) OutTraceE("UpdateWindow: ERROR er=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extRedrawWindow(HWND hWnd, const RECT *lprcUpdate, HRGN hrgnUpdate, UINT flags) +{ + RECT rcUpdate; + BOOL ret; + + OutTraceDW("RedrawWindow: hwnd=%x flags=%x\n", hWnd, flags); + + rcUpdate = *lprcUpdate; + // avoid redrawing the whole desktop + if(dxw.Windowize && dxw.IsRealDesktop(hWnd)) hWnd=dxw.GethWnd(); + if(dxw.IsFullScreen()){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_STRETCHED: + rcUpdate = dxw.MapClientRect((LPRECT)lprcUpdate); + break; + default: + break; + } + } + + ret = (*pRedrawWindow)(hWnd, &rcUpdate, hrgnUpdate, flags); + if(ret) OutTraceE("RedrawWindow ERROR: err=%d\n", GetLastError()); + return ret; +} + + +BOOL WINAPI extGetWindowPlacement(HWND hwnd, WINDOWPLACEMENT *lpwndpl) +{ + BOOL ret; + OutTraceDW("GetWindowPlacement: hwnd=%x\n", hwnd); + + if(dxw.IsRealDesktop(hwnd)){ + OutTraceDW("GetWindowPlacement: remapping hwnd=%x->%x\n", hwnd, dxw.GethWnd()); + hwnd=dxw.GethWnd(); + } + + ret=(*pGetWindowPlacement)(hwnd, lpwndpl); + OutTraceDW("GetWindowPlacement: flags=%x showCmd=%x MinPosition=(%d,%d) MaxPosition=(%d,%d) NormalPosition=(%d,%d)-(%d,%d)\n", + lpwndpl->flags, lpwndpl->showCmd, + lpwndpl->ptMinPosition.x, lpwndpl->ptMinPosition.y, + lpwndpl->ptMaxPosition.x, lpwndpl->ptMaxPosition.y, + lpwndpl->rcNormalPosition.left, lpwndpl->rcNormalPosition.top, lpwndpl->rcNormalPosition.right, lpwndpl->rcNormalPosition.bottom); + + switch (lpwndpl->showCmd){ + case SW_SHOW: + if (dxw.IsFullScreen()){ + lpwndpl->showCmd = SW_MAXIMIZE; + OutTraceDW("GetWindowPlacement: forcing SW_MAXIMIZE state\n"); + } + break; + } + if(!ret) OutTraceE("GetWindowPlacement: ERROR er=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extSetWindowPlacement(HWND hwnd, WINDOWPLACEMENT *lpwndpl) +{ + BOOL ret; + OutTraceDW("SetWindowPlacement: hwnd=%x\n", hwnd); + + if(dxw.IsRealDesktop(hwnd)){ + OutTraceDW("SetWindowPlacement: remapping hwnd=%x->%x\n", hwnd, dxw.GethWnd()); + hwnd=dxw.GethWnd(); + } + + OutTraceDW("SetWindowPlacement: flags=%x showCmd=%x MinPosition=(%d,%d) MaxPosition=(%d,%d) NormalPosition=(%d,%d)-(%d,%d)\n", + lpwndpl->flags, lpwndpl->showCmd, + lpwndpl->ptMinPosition.x, lpwndpl->ptMinPosition.y, + lpwndpl->ptMaxPosition.x, lpwndpl->ptMaxPosition.y, + lpwndpl->rcNormalPosition.left, lpwndpl->rcNormalPosition.top, lpwndpl->rcNormalPosition.right, lpwndpl->rcNormalPosition.bottom); + + switch (lpwndpl->showCmd){ + case SW_MAXIMIZE: + if (dxw.IsFullScreen()){ + lpwndpl->showCmd = SW_SHOW; + OutTraceDW("SetWindowPlacement: forcing SW_SHOW state\n"); + } + break; + } + ret=(*pSetWindowPlacement)(hwnd, lpwndpl); + if(!ret) OutTraceE("SetWindowPlacement: ERROR er=%d\n", GetLastError()); + return ret; +} + +HWND WINAPI extSetCapture(HWND hwnd) +{ + HWND ret; + OutTraceDW("SetCapture: hwnd=%x\n", hwnd); + ret=(*pSetCapture)(hwnd); + OutTraceDW("SetCapture: ret=%x\n", ret); + return ret; +} + +HWND WINAPI extGetActiveWindow(void) +{ + HWND ret; + ret=(*pGetActiveWindow)(); + if(dxw.Windowize && dxw.IsFullScreen()) { + OutTraceDW("GetActiveWindow: ret=%x->%x\n", ret, dxw.GethWnd()); + return dxw.GethWnd(); + } + return ret; +} + +HWND WINAPI extGetForegroundWindow(void) +{ + HWND ret; + ret=(*pGetForegroundWindow)(); + if(dxw.Windowize && dxw.IsFullScreen()) { + OutTraceDW("GetForegroundWindow: ret=%x->%x\n", ret, dxw.GethWnd()); + return dxw.GethWnd(); + } + return ret; +} + +BOOL WINAPI extIsWindowVisible(HWND hwnd) +{ + BOOL ret; + ret=(*pIsWindowVisible)(hwnd); + OutTraceB("IsWindowVisible: hwnd=%x ret=%x\n", hwnd, ret); + if(dxw.IsDesktop(hwnd) && !ret){ + OutTraceDW("IsWindowVisible: FORCING ret=TRUE\n"); + ret=TRUE; + } + return ret; +} + +BOOL WINAPI extSystemParametersInfoA(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni) +{ + BOOL ret; + OutTraceDW("SystemParametersInfoA: Action=%x Param=%x WinIni=%x\n", uiAction, uiParam, fWinIni); + switch(uiAction){ + case SPI_SETKEYBOARDDELAY: + case SPI_SETKEYBOARDSPEED: + OutTraceDW("SystemParametersInfoA: bypass action=%x\n", uiAction); + return TRUE; + break; + } + ret=(*pSystemParametersInfoA)(uiAction, uiParam, pvParam, fWinIni); + if(uiAction==SPI_GETWORKAREA){ + LPRECT cli = (LPRECT)pvParam; + *cli = dxw.GetScreenRect(); + OutTraceDW("SystemParametersInfoA: resized client workarea rect=(%d,%d)-(%d,%d)\n", cli->left, cli->top, cli->right, cli->bottom); + } + return ret; +} + +BOOL WINAPI extSystemParametersInfoW(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni) +{ + BOOL ret; + OutTraceDW("SystemParametersInfoW: Action=%x Param=%x WinIni=%x\n", uiAction, uiParam, fWinIni); + switch(uiAction){ + case SPI_SETKEYBOARDDELAY: + case SPI_SETKEYBOARDSPEED: + OutTraceDW("SystemParametersInfoW: bypass action=%x\n", uiAction); + return TRUE; + break; + } + ret=(*pSystemParametersInfoW)(uiAction, uiParam, pvParam, fWinIni); + if(uiAction==SPI_GETWORKAREA){ + LPRECT cli = (LPRECT)pvParam; + *cli = dxw.GetScreenRect(); + OutTraceDW("SystemParametersInfoW: resized client workarea rect=(%d,%d)-(%d,%d)\n", cli->left, cli->top, cli->right, cli->bottom); + } + return ret; +} + +#undef OutTraceDW +#define OutTraceDW OutTrace + +UINT_PTR WINAPI extSetTimer(HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc) +{ + UINT uShiftedElapse; + UINT_PTR ret; + // beware: the quicker the time flows, the more the time clicks are incremented, + // and the lesser the pauses must be lasting! Shift operations are reverted in + // GetSystemTime vs. Sleep or SetTimer + uShiftedElapse = dxw.StretchTime(uElapse); + OutTraceDW("SetTimer: hwnd=%x TimerFunc=%x elapse=%d->%d timeshift=%d\n", hWnd, lpTimerFunc, uElapse, uShiftedElapse, dxw.TimeShift); + ret = (*pSetTimer)(hWnd, nIDEvent, uShiftedElapse, lpTimerFunc); + if(ret) dxw.PushTimer(hWnd, ret, uElapse, lpTimerFunc); + OutTraceDW("SetTimer: IDEvent=%x ret=%x\n", nIDEvent, ret); + return ret; +} + +BOOL WINAPI extKillTimer(HWND hWnd, UINT_PTR uIDEvent) +{ + BOOL ret; + OutTraceDW("KillTimer: hwnd=%x IDEvent=%x\n", hWnd, uIDEvent); + ret = (*pKillTimer)(hWnd, uIDEvent); + OutTraceDW("KillTimer: ret=%x\n", ret); + if(ret) dxw.PopTimer(hWnd, uIDEvent); + return ret; +} + +BOOL WINAPI extGetUpdateRect(HWND hWnd, LPRECT lpRect, BOOL bErase) +{ + BOOL ret; + OutTraceDW("GetUpdateRect: hwnd=%x Erase=%x\n", hWnd, bErase); + ret = (*pGetUpdateRect)(hWnd, lpRect, bErase); + if(ret){ + OutTraceDW("GetUpdateRect: rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + if(dxw.IsFullScreen()){ + dxw.UnmapClient(lpRect); + OutTraceDW("GetUpdateRect: FIXED rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + } + else + OutTraceE("GetUpdateRect ERROR: err=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extGetCursorInfo(PCURSORINFO pci) +{ + BOOL ret; + OutTraceDW("GetCursorInfo\n"); + ret = (*pGetCursorInfo)(pci); + if(ret){ + OutTraceDW("GetCursorInfo: flags=%x hcursor=%x pos=(%d,%d)\n", pci->flags, pci->hCursor, pci->ptScreenPos.x, pci->ptScreenPos.y); + if(dxw.IsFullScreen()){ + dxw.UnmapClient(&(pci->ptScreenPos)); + OutTraceDW("GetCursorInfo: FIXED pos=(%d,%d)\n", pci->ptScreenPos.x, pci->ptScreenPos.y); + } + } + else + OutTraceE("GetCursorInfo ERROR: err=%d\n", GetLastError()); + return ret; +} + +// --- to be hooked .... + +HWND WINAPI extWindowFromPoint(POINT Point) +{ + HWND ret; + OutTraceDW("WindowFromPoint: point=(%d,%d)\n", Point.x, Point.y); + if(dxw.IsFullScreen()){ + dxw.UnmapWindow(&Point); + OutTraceDW("WindowFromPoint: FIXED point=(%d,%d)\n", Point.x, Point.y); + } + ret = (*pWindowFromPoint)(Point); + OutTraceDW("WindowFromPoint: hwnd=%x\n", ret); + return ret; +} + +HWND WINAPI extChildWindowFromPoint(HWND hWndParent, POINT Point) +{ + HWND ret; + OutTraceDW("ChildWindowFromPoint: hWndParent=%x point=(%d,%d)\n", hWndParent, Point.x, Point.y); + if(dxw.IsDesktop(hWndParent) && dxw.IsFullScreen() && dxw.Windowize){ + dxw.UnmapClient(&Point); + OutTraceDW("ChildWindowFromPoint: FIXED point=(%d,%d)\n", Point.x, Point.y); + } + ret = (*pChildWindowFromPoint)(hWndParent, Point); + OutTraceDW("ChildWindowFromPoint: hwnd=%x\n", ret); + return ret; +} + +HWND WINAPI extChildWindowFromPointEx(HWND hWndParent, POINT Point, UINT uFlags) +{ + HWND ret; + OutTraceDW("ChildWindowFromPoint: hWndParent=%x point=(%d,%d) flags=%x\n", hWndParent, Point.x, Point.y, uFlags); + if(dxw.IsDesktop(hWndParent) && dxw.IsFullScreen() && dxw.Windowize){ + dxw.UnmapClient(&Point); + OutTraceDW("ChildWindowFromPointEx: FIXED point=(%d,%d)\n", Point.x, Point.y); + } + ret = (*pChildWindowFromPointEx)(hWndParent, Point, uFlags); + OutTraceDW("ChildWindowFromPointEx: hwnd=%x\n", ret); + return ret; +} + +BOOL extGetMonitorInfo(HMONITOR hMonitor, LPMONITORINFO lpmi, GetMonitorInfo_Type pGetMonitorInfo) +{ + BOOL res; + OutTraceDW("GetMonitorInfo: hMonitor=%x mi=MONITORINFO%s\n", hMonitor, lpmi->cbSize==sizeof(MONITORINFO)?"":"EX"); + res=(*pGetMonitorInfo)(hMonitor, lpmi); + //v2.03.15 - must fix the coordinates also in case of error: that may depend on the windowed mode. + if(dxw.Windowize){ + OutTraceDW("GetMonitorInfo: FIX Work=(%d,%d)-(%d,%d) Monitor=(%d,%d)-(%d,%d) -> (%d,%d)-(%d,%d)\n", + lpmi->rcWork.left, lpmi->rcWork.top, lpmi->rcWork.right, lpmi->rcWork.bottom, + lpmi->rcMonitor.left, lpmi->rcMonitor.top, lpmi->rcMonitor.right, lpmi->rcMonitor.bottom, + 0, 0, dxw.GetScreenWidth(), dxw.GetScreenHeight()); + lpmi->rcWork = dxw.GetScreenRect(); + lpmi->rcMonitor = dxw.GetScreenRect(); + res=TRUE; + } + else + OutTraceE("GetMonitorInfo: ERROR err=%d\n", GetLastError()); + + return res; +} + +BOOL WINAPI extGetMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpmi) +{ + return extGetMonitorInfo(hMonitor, lpmi, pGetMonitorInfoA); +} + +BOOL WINAPI extGetMonitorInfoW(HMONITOR hMonitor, LPMONITORINFO lpmi) +{ + return extGetMonitorInfo(hMonitor, lpmi, pGetMonitorInfoW); +} + +int WINAPI extGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase) +{ + int regionType; + regionType=(*pGetUpdateRgn)(hWnd, hRgn, bErase); + OutTraceDW("GetUpdateRgn: hwnd=%x hrgn=%x erase=%x regionType=%x(%s)\n", + hWnd, hRgn, bErase, regionType, ExplainRegionType(regionType)); + + if(dxw.IsFullScreen()){ + if(regionType == SIMPLEREGION){ + RECT rc; + if(!pGetRgnBox) pGetRgnBox=GetRgnBox; + regionType = (*pGetRgnBox)(hRgn, &rc); + OutTraceDW("GetUpdateRgn: regionType=%x(%s) box=(%d,%d)-(%d,%d)\n", + regionType, ExplainRegionType(regionType), rc.left, rc.top, rc.right, rc.bottom); + if(regionType == SIMPLEREGION){ + dxw.UnmapClient(&rc); + if(SetRectRgn(hRgn, rc.left, rc.top, rc.right, rc.bottom )){ + // success + OutTraceDW("GetUpdateRgn: FIXED box=(%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom); + } + } + } +#if 0 + if(regionType == COMPLEXREGION){ + RECT rc; + if(!pGetRgnBox) pGetRgnBox=GetRgnBox; + regionType = (*pGetRgnBox)(hRgn, &rc); + OutTraceDW("GetUpdateRgn: regionType=%x(%s) box=(%d,%d)-(%d,%d)\n", + regionType, ExplainRegionType(regionType), rc.left, rc.top, rc.right, rc.bottom); + if(regionType == COMPLEXREGION){ + //dxw.UnmapClient(&rc); + //if(SetRectRgn(hRgn, rc.left, rc.top, rc.right, rc.bottom )){ + if(SetRectRgn(hRgn, 0, 0, dxw.GetScreenWidth(), dxw.GetScreenHeight())){ + // success + OutTraceDW("GetUpdateRgn: FIXED box=(%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom); + } + } + } +#endif + } + + return regionType; +} + +#ifdef TRACEPALETTE +UINT WINAPI extGetDIBColorTable(HDC hdc, UINT uStartIndex, UINT cEntries, RGBQUAD *pColors) +{ + UINT ret; + OutTraceDW("GetDIBColorTable: hdc=%x start=%d entries=%d\n", hdc, uStartIndex, cEntries); + + //if((OBJ_DC == GetObjectType(hdc)) && (dxw.dwFlags1 & EMULATESURFACE)){ + // //extern PALETTEENTRY PalEntries[256]; + // extern DWORD *PaletteEntries; + // if((uStartIndex+cEntries) > 256) cEntries = 256 - uStartIndex; + // for(UINT i=0; i 256) cEntries = 256 - uStartIndex; + // for(UINT i=0; ileft, lpRect->top, lpRect->right, lpRect->bottom); + else + OutTrace("ValidateRect: hwnd=%x rect=NULL\n", hWnd); + } + ret = (*pValidateRect)(hWnd, lpRect); + return ret; +} + +int WINAPI extGetWindowTextA(HWND hWnd, LPTSTR lpString, int nMaxCount) +{ + // purpose of this wrapped call is to clear the FPS indicator (format " ~ (%d FPS)") + // from the window title, if present. It crashes games such as "Panzer General 3 Scorched Earth" + // when FPS on window title is activated. + int ret; + OutTraceDW("GetWindowTextA: hwnd=%x MaxCount=%d\n", hWnd, nMaxCount); + ret=(*pGetWindowTextA)(hWnd, lpString, nMaxCount); + if(ret) OutTraceDW("GetWindowTextA: ret=%d String=\"%s\"\n", ret, lpString); + if (ret && (dxw.dwFlags2 & SHOWFPS) && dxw.ishWndFPS(hWnd)){ + char *p; + p=strstr(lpString, " ~ ("); + if(p){ + *p = NULL; + ret = strlen(lpString); + OutTraceDW("GetWindowTextA: FIXED ret=%d String=\"%s\"\n", ret, lpString); + } + } + return ret; +} +#endif + +BOOL WINAPI extBringWindowToTop(HWND hwnd) +{ + BOOL res; + OutTraceDW("BringWindowToTop: hwnd=%x\n", hwnd); + if(dxw.dwFlags5 & UNLOCKZORDER) return TRUE; + res=(*pBringWindowToTop)(hwnd); + return res; +} + +BOOL WINAPI extSetForegroundWindow(HWND hwnd) +{ + BOOL res; + OutTraceDW("SetForegroundWindow: hwnd=%x\n", hwnd); + if(dxw.dwFlags5 & UNLOCKZORDER) return TRUE; + res=(*pSetForegroundWindow)(hwnd); + return res; +} + +/* +HOOKPROC glpMouseHookProcessFunction; +LRESULT CALLBACK extMouseHookProc(int code, WPARAM wParam, LPARAM lParam) +{ + LRESULT ret; + OutTrace("HookProc intercepted: code=%x wParam=%x lParam=%x\n", code, wParam, lParam); + MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lParam; + if (pMouseStruct != NULL){ + dxw.UnmapWindow(&(pMouseStruct->pt)); + } + ret= (*glpMouseHookProcessFunction)(code, wParam, lParam); + return ret; +} +*/ + +HOOKPROC glpMessageHookProcessFunction; + +LRESULT CALLBACK extMessageHookProc(int code, WPARAM wParam, LPARAM lParam) +{ + LRESULT ret; + OutTrace("MessageHookProc: code=%x wParam=%x lParam=%x\n", code, wParam, lParam); + MSG * pMessage = (MSG *)lParam; + ret = NULL; + if(pMessage){ + UINT message = pMessage->message; + if ((message >= 0x600) || // custom messages + ((message >= WM_KEYFIRST) && (message <= WM_KEYLAST)) || // keyboard messages + ((message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST)) // mouse messages + ) + ret = (*glpMessageHookProcessFunction)(code, wParam, lParam); + } + return ret; +} + +HHOOK WINAPI extSetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId) +{ + HHOOK ret; + if(dxw.dwFlags5 & EASPORTSHACK){ + if(idHook == WH_MOUSE) return NULL; + if(idHook == WH_GETMESSAGE) { + glpMessageHookProcessFunction = lpfn; + lpfn=extMessageHookProc; + } + } + // v2.03.39: "One Must Fall Battlegrounds" keyboard fix + if((idHook == WH_KEYBOARD) && (dwThreadId == NULL)) dwThreadId = GetCurrentThreadId(); + + ret=(*pSetWindowsHookEx)(idHook, lpfn, hMod, dwThreadId); + + return ret; +} + + +HRESULT WINAPI extMessageBoxTimeoutA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, WORD wLanguageId, DWORD dwMilliseconds) +{ + HRESULT res; + if(1) dwMilliseconds=1000; + res=(*pMessageBoxTimeoutA)(hWnd, lpText, lpCaption, uType, wLanguageId, dwMilliseconds); + return res; +} + +HRESULT WINAPI extMessageBoxTimeoutW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType, WORD wLanguageId, DWORD dwMilliseconds) +{ + HRESULT res; + if(1) dwMilliseconds=1000; + res=(*pMessageBoxTimeoutW)(hWnd, lpText, lpCaption, uType, wLanguageId, dwMilliseconds); + return res; +} + +HDESK WINAPI extCreateDesktop( LPCTSTR lpszDesktop, LPCTSTR lpszDevice, DEVMODE *pDevmode, DWORD dwFlags, ACCESS_MASK dwDesiredAccess, LPSECURITY_ATTRIBUTES lpsa) +{ + //OutTrace("CreateDesktop: SUPPRESS Desktop=%s Device=%s flags=%x access=%x\n", lpszDesktop, lpszDevice, dwFlags, dwDesiredAccess); + OutTraceDW("CreateDesktop: SUPPRESS flags=%x access=%x\n", dwFlags, dwDesiredAccess); + return (HDESK)0xDEADBEEF; // fake handle + //return (HDESK)NULL; // fake handle +} + +BOOL WINAPI extSwitchDesktop(HDESK hDesktop) +{ + OutTraceDW("SwitchDesktop: SUPPRESS hDesktop=%x\n", hDesktop); + return TRUE; +} + +HDESK WINAPI extOpenDesktop(LPTSTR lpszDesktop, DWORD dwFlags, BOOL fInherit, ACCESS_MASK dwDesiredAccess) +{ + OutTraceDW("CreateDesktop: SUPPRESS flags=%x access=%x\n", dwFlags, dwDesiredAccess); + return (HDESK)0xDEADBEEF; // fake handle + //return (HDESK)NULL; // fake handle +} + +BOOL WINAPI extCloseDesktop(HDESK hDesktop) +{ + OutTraceDW("CloseDesktop: SUPPRESS hDesktop=%x\n", hDesktop); + return TRUE; +} + +INT_PTR WINAPI extDialogBoxParamA(HINSTANCE hInstance, LPCTSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam) +{ + BOOL ret, FullScreen; + FullScreen = dxw.IsFullScreen(); + OutTraceDW("DialogBoxParamA: FullScreen=%x TemplateName=\"%s\" WndParent=%x\n", + FullScreen, sTemplateName(lpTemplateName), hWndParent); + dxw.SetFullScreen(FALSE); + ret = (*pDialogBoxParamA)(hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam); + dxw.SetFullScreen(FullScreen); + OutTraceDW("DialogBoxParamA: ret=%x\n", ret); + return ret; +} + +BOOL WINAPI extIsZoomed(HWND hWnd) +{ + BOOL ret; + ret = (*pIsZoomed)(hWnd); + OutTraceDW("IsZoomed: hwnd=%x ret=%x\n", hWnd, ret); + //if(dxw.IsFullScreen()) ret = FALSE; + return ret; +} + +BOOL WINAPI extIsIconic(HWND hWnd) +{ + BOOL ret; + ret = (*pIsIconic)(hWnd); + OutTraceDW("IsIconic: hwnd=%x ret=%x\n", hWnd, ret); + //return FALSE; + return ret; +} + +BOOL extScrollWindow(HWND hWnd, int XAmount, int YAmount, const RECT *lpRect, const RECT *lpClipRect) +{ + RECT Rect, ClipRect; + BOOL res; + + OutTraceDW("ScrollWindow: hwnd=%x amount=(%d,%d) rect=(%d,%d)-(%d,%d) clip=(%d,%d)-(%d,%d)\n", + hWnd, XAmount, YAmount, + lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, + lpClipRect->left, lpClipRect->top, lpClipRect->right, lpClipRect->bottom); + + Rect = *lpRect; + ClipRect = *lpClipRect; + if(dxw.Windowize && dxw.IsFullScreen()){ + dxw.MapClient(&XAmount, &YAmount); + dxw.MapClient(&Rect); + dxw.MapClient(&ClipRect); + } + + res=(*pScrollWindow)(hWnd, XAmount, YAmount, (const RECT *)&Rect, (const RECT *)&ClipRect); + if(!res) OutTraceE("ScrollWindow ERROR: err=%d\n", GetLastError()); + return res; +} + +#if 0 +// avoid invalidating whole desktop!!! +BOOL InvalidateRgn( + _In_ HWND hWnd, + _In_ HRGN hRgn, + _In_ BOOL bErase +); + +#endif + +HWND WINAPI extGetParent(HWND hWnd) +{ + HWND ret; + + ret = (*pGetParent)(hWnd); + OutTraceB("GetParent: hwnd=%x ret=%x\n", hWnd, ret); + + if(dxw.IsFullScreen()){ + if(ret == dxw.GethWnd()) { + OutTraceDW("GetParent: setting desktop reached\n"); + ret = 0; // simulate reaching the desktop + } + } + + return ret; +} + +BOOL WINAPI extInvalidateRgn(HWND hWnd, HRGN hRgn, BOOL bErase) +{ + OutTraceDW("InvalidateRgn: hwnd=%x hrgn=%x erase=%x\n", hWnd, hRgn, bErase); + + if(dxw.IsFullScreen()){ + if (dxw.IsRealDesktop(hWnd) && bErase) return true; + } + + return (*pInvalidateRgn)(hWnd, hRgn, bErase); +} diff --git a/dll/user32.cpp b/dll/user32.cpp index 8d0adf1..425ce1b 100644 --- a/dll/user32.cpp +++ b/dll/user32.cpp @@ -11,17 +11,16 @@ #include "dxhook.h" #include "hddraw.h" #include "dxhelper.h" +#include "shareddc.hpp" +#include #define FIXCHILDSIZE FALSE +#define _Warn(s) MessageBox(0, s, "to do", MB_ICONEXCLAMATION) BOOL IsChangeDisplaySettingsHotPatched = FALSE; extern BOOL bFlippedDC; extern HDC hFlippedDC; -//typedef BOOL (WINAPI *ValidateRect_Type)(HWND, const RECT *); -//BOOL WINAPI extValidateRect(HWND, const RECT *); -//ValidateRect_Type pValidateRect = NULL; - //typedef BOOL (WINAPI *EnumDisplayMonitors_Type)(HDC, LPCRECT, MONITORENUMPROC, LPARAM); //EnumDisplayMonitors_Type pEnumDisplayMonitors = NULL; //BOOL WINAPI extEnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM); @@ -62,10 +61,39 @@ HDESK WINAPI extOpenDesktop(LPTSTR, DWORD, BOOL, ACCESS_MASK); typedef BOOL (WINAPI *CloseDesktop_Type)(HDESK); CloseDesktop_Type pCloseDesktop = NULL; BOOL WINAPI extCloseDesktop(HDESK); - +typedef int (WINAPI *ValidateRect_Type)(HWND, const RECT *); +ValidateRect_Type pValidateRect = NULL; +int WINAPI extValidateRect(HWND, const RECT *); +typedef BOOL (WINAPI *ScrollWindow_Type)(HWND, int, int, const RECT *, const RECT *); +ScrollWindow_Type pScrollWindow = NULL; +BOOL extScrollWindow(HWND, int, int, const RECT *, const RECT *); typedef INT_PTR (WINAPI *DialogBoxParamA_Type)(HINSTANCE, LPCTSTR, HWND, DLGPROC, LPARAM); DialogBoxParamA_Type pDialogBoxParamA = NULL; INT_PTR WINAPI extDialogBoxParamA(HINSTANCE, LPCTSTR, HWND, DLGPROC, LPARAM); +typedef HWND (WINAPI *GetParent_Type)(HWND); +GetParent_Type pGetParent = NULL; +HWND WINAPI extGetParent(HWND); +typedef BOOL (WINAPI *InvalidateRgn_Type)(HWND, HRGN, BOOL); +InvalidateRgn_Type pInvalidateRgn = NULL; +BOOL WINAPI extInvalidateRgn(HWND, HRGN, BOOL); +typedef BOOL (WINAPI *InvertRect_Type)(HDC, const RECT *); +InvertRect_Type pInvertRect = NULL; +BOOL WINAPI extInvertRect(HDC, const RECT *); +typedef BOOL (WINAPI *ScrollDC_Type)(HDC, int, int, const RECT *, const RECT *, HRGN, LPRECT); +ScrollDC_Type pScrollDC = NULL; +BOOL WINAPI extScrollDC(HDC, int, int, const RECT *, const RECT *, HRGN, LPRECT); +typedef BOOL (WINAPI *DrawIcon_Type)(HDC hDC, int X, int Y, HICON hIcon); +DrawIcon_Type pDrawIcon = NULL; +BOOL WINAPI extDrawIcon(HDC hDC, int X, int Y, HICON hIcon); +typedef BOOL (WINAPI *DrawIconEx_Type)(HDC, int, int, HICON, int, int, UINT, HBRUSH, UINT); +DrawIconEx_Type pDrawIconEx = NULL; +BOOL WINAPI extDrawIconEx(HDC, int, int, HICON, int, int, UINT, HBRUSH, UINT); +typedef BOOL (WINAPI *DrawCaption_Type)(HWND, HDC, LPCRECT, UINT); +DrawCaption_Type pDrawCaption = NULL; +BOOL WINAPI extDrawCaption(HWND, HDC, LPCRECT, UINT); +typedef BOOL (WINAPI *PaintDesktop_Type)(HDC); +PaintDesktop_Type pPaintDesktop = NULL; +BOOL WINAPI extPaintDesktop(HDC); #ifdef TRACEPALETTE typedef UINT (WINAPI *GetDIBColorTable_Type)(HDC, UINT, UINT, RGBQUAD *); @@ -86,7 +114,7 @@ static HookEntry_Type Hooks[]={ {HOOK_HOT_CANDIDATE, "ChangeDisplaySettingsExW", (FARPROC)NULL, (FARPROC *)&pChangeDisplaySettingsExW, (FARPROC)extChangeDisplaySettingsExW}, {HOOK_HOT_CANDIDATE, "GetMonitorInfoA", (FARPROC)GetMonitorInfoA, (FARPROC *)&pGetMonitorInfoA, (FARPROC)extGetMonitorInfoA}, {HOOK_HOT_CANDIDATE, "GetMonitorInfoW", (FARPROC)GetMonitorInfoW, (FARPROC *)&pGetMonitorInfoW, (FARPROC)extGetMonitorInfoW}, - {HOOK_IAT_CANDIDATE, "ShowCursor", (FARPROC)ShowCursor, (FARPROC *)&pShowCursor, (FARPROC)extShowCursor}, + {HOOK_HOT_CANDIDATE, "ShowCursor", (FARPROC)ShowCursor, (FARPROC *)&pShowCursor, (FARPROC)extShowCursor}, {HOOK_IAT_CANDIDATE, "CreateDialogIndirectParamA", (FARPROC)CreateDialogIndirectParamA, (FARPROC *)&pCreateDialogIndirectParam, (FARPROC)extCreateDialogIndirectParam}, {HOOK_IAT_CANDIDATE, "CreateDialogParamA", (FARPROC)CreateDialogParamA, (FARPROC *)&pCreateDialogParam, (FARPROC)extCreateDialogParam}, {HOOK_IAT_CANDIDATE, "MoveWindow", (FARPROC)MoveWindow, (FARPROC *)&pMoveWindow, (FARPROC)extMoveWindow}, @@ -99,6 +127,8 @@ static HookEntry_Type Hooks[]={ {HOOK_HOT_CANDIDATE, "CreateWindowExW", (FARPROC)CreateWindowExW, (FARPROC *)&pCreateWindowExW, (FARPROC)extCreateWindowExW}, {HOOK_IAT_CANDIDATE, "RegisterClassExA", (FARPROC)RegisterClassExA, (FARPROC *)&pRegisterClassExA, (FARPROC)extRegisterClassExA}, {HOOK_IAT_CANDIDATE, "RegisterClassA", (FARPROC)RegisterClassA, (FARPROC *)&pRegisterClassA, (FARPROC)extRegisterClassA}, + {HOOK_IAT_CANDIDATE, "RegisterClassExW", (FARPROC)RegisterClassExW, (FARPROC *)&pRegisterClassExW, (FARPROC)extRegisterClassExW}, + {HOOK_IAT_CANDIDATE, "RegisterClassW", (FARPROC)RegisterClassW, (FARPROC *)&pRegisterClassW, (FARPROC)extRegisterClassW}, {HOOK_HOT_CANDIDATE, "GetSystemMetrics", (FARPROC)GetSystemMetrics, (FARPROC *)&pGetSystemMetrics, (FARPROC)extGetSystemMetrics}, {HOOK_HOT_CANDIDATE, "GetDesktopWindow", (FARPROC)GetDesktopWindow, (FARPROC *)&pGetDesktopWindow, (FARPROC)extGetDesktopWindow}, {HOOK_IAT_CANDIDATE, "CloseWindow", (FARPROC)NULL, (FARPROC *)&pCloseWindow, (FARPROC)extCloseWindow}, @@ -127,7 +157,7 @@ static HookEntry_Type Hooks[]={ {HOOK_HOT_CANDIDATE, "ChildWindowFromPoint", (FARPROC)ChildWindowFromPoint, (FARPROC *)&pChildWindowFromPoint, (FARPROC)extChildWindowFromPoint}, {HOOK_HOT_CANDIDATE, "ChildWindowFromPointEx", (FARPROC)ChildWindowFromPointEx, (FARPROC *)&pChildWindowFromPointEx, (FARPROC)extChildWindowFromPointEx}, {HOOK_HOT_CANDIDATE, "WindowFromPoint", (FARPROC)WindowFromPoint, (FARPROC *)&pWindowFromPoint, (FARPROC)extWindowFromPoint}, - {HOOK_HOT_CANDIDATE, "SetWindowsHookExA", (FARPROC)SetWindowsHookExA, (FARPROC *)&pSetWindowsHookEx, (FARPROC)extSetWindowsHookEx}, + {HOOK_HOT_REQUIRED , "SetWindowsHookExA", (FARPROC)SetWindowsHookExA, (FARPROC *)&pSetWindowsHookEx, (FARPROC)extSetWindowsHookEx}, //{HOOK_HOT_CANDIDATE, "MessageBoxTimeoutA", (FARPROC)NULL, (FARPROC *)&pMessageBoxTimeoutA, (FARPROC)extMessageBoxTimeoutA}, //{HOOK_HOT_CANDIDATE, "MessageBoxTimeoutW", (FARPROC)NULL, (FARPROC *)&pMessageBoxTimeoutW, (FARPROC)extMessageBoxTimeoutW}, @@ -144,52 +174,58 @@ static HookEntry_Type Hooks[]={ //{HOOK_IAT_CANDIDATE, "IsZoomed", (FARPROC)NULL, (FARPROC *)&pIsZoomed, (FARPROC)extIsZoomed}, //{HOOK_HOT_CANDIDATE, "IsIconic", (FARPROC)IsIconic, (FARPROC *)&pIsIconic, (FARPROC)extIsIconic}, + {HOOK_HOT_CANDIDATE, "ScrollDC", (FARPROC)NULL, (FARPROC *)&pScrollDC, (FARPROC)extScrollDC}, - {HOOK_HOT_CANDIDATE, "FillRect", (FARPROC)NULL, (FARPROC *)&pFillRect, (FARPROC)extFillRect}, - - {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator -}; - -static HookEntry_Type NoGDIHooks[]={ - {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator -}; - -static HookEntry_Type EmulateHooks[]={ - //{HOOK_IAT_CANDIDATE, "GetDC", (FARPROC)GetDC, (FARPROC *)&pGDIGetDC, (FARPROC)extGDIGetDC}, - //{HOOK_IAT_CANDIDATE, "GetDCEx", (FARPROC)GetDCEx, (FARPROC *)&pGDIGetDCEx, (FARPROC)extGDIGetDCEx}, - //{HOOK_IAT_CANDIDATE, "GetWindowDC", (FARPROC)GetWindowDC, (FARPROC *)&pGDIGetWindowDC, (FARPROC)extGDIGetWindowDC}, - //{HOOK_IAT_CANDIDATE, "ReleaseDC", (FARPROC)ReleaseDC, (FARPROC *)&pGDIReleaseDC, (FARPROC)extGDIReleaseDC}, - //{HOOK_IAT_CANDIDATE, "InvalidateRect", (FARPROC)InvalidateRect, (FARPROC *)&pInvalidateRect, (FARPROC)extInvalidateRect}, - {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator -}; - -static HookEntry_Type ScaledHooks[]={ - {HOOK_IAT_CANDIDATE, "FrameRect", (FARPROC)NULL, (FARPROC *)&pFrameRect, (FARPROC)extFrameRect}, - {HOOK_IAT_CANDIDATE, "TabbedTextOutA", (FARPROC)TabbedTextOutA, (FARPROC *)&pTabbedTextOutA, (FARPROC)extTabbedTextOutA}, - {HOOK_IAT_CANDIDATE, "DrawTextA", (FARPROC)DrawTextA, (FARPROC *)&pDrawText, (FARPROC)extDrawTextA}, - {HOOK_IAT_CANDIDATE, "DrawTextExA", (FARPROC)DrawTextExA, (FARPROC *)&pDrawTextEx, (FARPROC)extDrawTextExA}, - //{HOOK_HOT_CANDIDATE, "FillRect", (FARPROC)NULL, (FARPROC *)&pFillRect, (FARPROC)extFillRect}, - //{HOOK_IAT_CANDIDATE, "GetDC", (FARPROC)GetDC, (FARPROC *)&pGDIGetDC, (FARPROC)extGDIGetDC}, - //{HOOK_IAT_CANDIDATE, "GetDCEx", (FARPROC)NULL, (FARPROC *)&pGDIGetDCEx, (FARPROC)extGDIGetDCEx}, - //{HOOK_IAT_CANDIDATE, "GetWindowDC", (FARPROC)GetWindowDC, (FARPROC *)&pGDIGetWindowDC, (FARPROC)extGDIGetWindowDC}, - //{HOOK_IAT_CANDIDATE, "ReleaseDC", (FARPROC)ReleaseDC, (FARPROC *)&pGDIReleaseDC, (FARPROC)extGDIReleaseDC}, - {HOOK_IAT_CANDIDATE, "InvalidateRect", (FARPROC)InvalidateRect, (FARPROC *)&pInvalidateRect, (FARPROC)extInvalidateRect}, - //{HOOK_IAT_CANDIDATE, "ValidateRect", (FARPROC)ValidateRect, (FARPROC *)&pValidateRect, (FARPROC)extValidateRect}, {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator }; static HookEntry_Type RemapHooks[]={ - {HOOK_IAT_CANDIDATE, "ScreenToClient", (FARPROC)ScreenToClient, (FARPROC *)&pScreenToClient, (FARPROC)extScreenToClient}, - {HOOK_IAT_CANDIDATE, "ClientToScreen", (FARPROC)ClientToScreen, (FARPROC *)&pClientToScreen, (FARPROC)extClientToScreen}, - {HOOK_IAT_CANDIDATE, "GetClientRect", (FARPROC)GetClientRect, (FARPROC *)&pGetClientRect, (FARPROC)extGetClientRect}, - {HOOK_IAT_CANDIDATE, "GetWindowRect", (FARPROC)GetWindowRect, (FARPROC *)&pGetWindowRect, (FARPROC)extGetWindowRect}, - {HOOK_IAT_CANDIDATE, "MapWindowPoints", (FARPROC)MapWindowPoints, (FARPROC *)&pMapWindowPoints, (FARPROC)extMapWindowPoints}, - {HOOK_IAT_CANDIDATE, "GetUpdateRgn", (FARPROC)GetUpdateRgn, (FARPROC *)&pGetUpdateRgn, (FARPROC)extGetUpdateRgn}, + {HOOK_HOT_CANDIDATE, "ScreenToClient", (FARPROC)ScreenToClient, (FARPROC *)&pScreenToClient, (FARPROC)extScreenToClient}, + {HOOK_HOT_CANDIDATE, "ClientToScreen", (FARPROC)ClientToScreen, (FARPROC *)&pClientToScreen, (FARPROC)extClientToScreen}, + {HOOK_HOT_CANDIDATE, "GetClientRect", (FARPROC)GetClientRect, (FARPROC *)&pGetClientRect, (FARPROC)extGetClientRect}, + {HOOK_HOT_CANDIDATE, "GetWindowRect", (FARPROC)GetWindowRect, (FARPROC *)&pGetWindowRect, (FARPROC)extGetWindowRect}, + {HOOK_HOT_CANDIDATE, "MapWindowPoints", (FARPROC)MapWindowPoints, (FARPROC *)&pMapWindowPoints, (FARPROC)extMapWindowPoints}, + {HOOK_HOT_CANDIDATE, "GetUpdateRgn", (FARPROC)GetUpdateRgn, (FARPROC *)&pGetUpdateRgn, (FARPROC)extGetUpdateRgn}, //{HOOK_IAT_CANDIDATE, "GetUpdateRect", (FARPROC)GetUpdateRect, (FARPROC *)&pGetUpdateRect, (FARPROC)extGetUpdateRect}, //{HOOK_IAT_CANDIDATE, "RedrawWindow", (FARPROC)RedrawWindow, (FARPROC *)&pRedrawWindow, (FARPROC)extRedrawWindow}, {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator }; +static HookEntry_Type SyscallHooks[]={ + {HOOK_IAT_CANDIDATE, "FrameRect", (FARPROC)FrameRect, (FARPROC *)&pFrameRect, (FARPROC)extFrameRect}, + {HOOK_IAT_CANDIDATE, "RedrawWindow", (FARPROC)RedrawWindow, (FARPROC *)&pRedrawWindow, (FARPROC)extRedrawWindow}, + {HOOK_IAT_CANDIDATE, "GetParent", (FARPROC)GetParent, (FARPROC *)&pGetParent, (FARPROC)extGetParent}, + {HOOK_HOT_CANDIDATE, "InvalidateRgn", (FARPROC)InvalidateRgn, (FARPROC *)&pInvalidateRgn, (FARPROC)extInvalidateRgn}, + {HOOK_IAT_CANDIDATE, "TabbedTextOutA", (FARPROC)TabbedTextOutA, (FARPROC *)&pTabbedTextOutA, (FARPROC)extTabbedTextOutA}, + {HOOK_IAT_CANDIDATE, "TabbedTextOutW", (FARPROC)TabbedTextOutW, (FARPROC *)&pTabbedTextOutW, (FARPROC)extTabbedTextOutW}, + {HOOK_IAT_CANDIDATE, "ScrollDC", (FARPROC)ScrollDC, (FARPROC *)&pScrollDC, (FARPROC)extScrollDC}, + {HOOK_IAT_CANDIDATE, "InvalidateRect", (FARPROC)InvalidateRect, (FARPROC *)&pInvalidateRect, (FARPROC)extInvalidateRect}, + {HOOK_IAT_CANDIDATE, "DrawTextA", (FARPROC)DrawTextA, (FARPROC *)&pDrawTextA, (FARPROC)extDrawTextA}, + {HOOK_IAT_CANDIDATE, "DrawTextExA", (FARPROC)DrawTextExA, (FARPROC *)&pDrawTextExA, (FARPROC)extDrawTextExA}, + {HOOK_IAT_CANDIDATE, "DrawTextW", (FARPROC)DrawTextW, (FARPROC *)&pDrawTextW, (FARPROC)extDrawTextW}, + {HOOK_IAT_CANDIDATE, "DrawTextExW", (FARPROC)DrawTextExW, (FARPROC *)&pDrawTextExW, (FARPROC)extDrawTextExW}, + {HOOK_HOT_CANDIDATE, "FillRect", (FARPROC)NULL, (FARPROC *)&pFillRect, (FARPROC)extFillRect}, + {HOOK_HOT_CANDIDATE, "InvertRect", (FARPROC)NULL, (FARPROC *)&pInvertRect, (FARPROC)extInvertRect}, + {HOOK_HOT_CANDIDATE, "DrawIcon", (FARPROC)NULL, (FARPROC *)&pDrawIcon, (FARPROC)extDrawIcon}, + {HOOK_HOT_CANDIDATE, "DrawIconEx", (FARPROC)NULL, (FARPROC *)&pDrawIconEx, (FARPROC)extDrawIconEx}, + {HOOK_HOT_CANDIDATE, "DrawCaption", (FARPROC)NULL, (FARPROC *)&pDrawCaption, (FARPROC)extDrawCaption}, + //TODO {HOOK_HOT_CANDIDATE, "DrawEdge", (FARPROC)NULL, (FARPROC *)&pDrawEdge, (FARPROC)extDrawEdge}, + //TODO {HOOK_HOT_CANDIDATE, "DrawFocusRect", (FARPROC)NULL, (FARPROC *)&pDrawFocusRect, (FARPROC)extDrawFocusRect}, + //TODO {HOOK_HOT_CANDIDATE, "DrawFrameControl", (FARPROC)NULL, (FARPROC *)&pDrawFrameControl, (FARPROC)extDrawFrameControl}, + //TODO {HOOK_HOT_CANDIDATE, "DrawStateA", (FARPROC)NULL, (FARPROC *)&pDrawStateA, (FARPROC)extDrawStateA}, + //TODO {HOOK_HOT_CANDIDATE, "DrawStateW", (FARPROC)NULL, (FARPROC *)&pDrawStateW, (FARPROC)extDrawStateW}, + //TODO {HOOK_HOT_CANDIDATE, "GrayStringA", (FARPROC)NULL, (FARPROC *)&pGrayStringA, (FARPROC)extGrayStringA}, + //TODO {HOOK_HOT_CANDIDATE, "GrayStringW", (FARPROC)NULL, (FARPROC *)&pGrayStringW, (FARPROC)extGrayStringW}, + //TODO {HOOK_HOT_CANDIDATE, "PaintDesktop", (FARPROC)NULL, (FARPROC *)&pPaintDesktop, (FARPROC)extPaintDesktop}, + {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator +}; + +static HookEntry_Type ScaledHooks[]={ + {HOOK_IAT_CANDIDATE, "ValidateRect", (FARPROC)ValidateRect, (FARPROC *)&pValidateRect, (FARPROC)extValidateRect}, + {HOOK_IAT_CANDIDATE, "ScrollWindow", (FARPROC)ScrollWindow, (FARPROC *)&pScrollWindow, (FARPROC)extScrollWindow}, + {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator +}; + static HookEntry_Type PeekAllHooks[]={ {HOOK_IAT_CANDIDATE, "PeekMessageA", (FARPROC)NULL, (FARPROC *)&pPeekMessage, (FARPROC)extPeekMessage}, {HOOK_IAT_CANDIDATE, "PeekMessageW", (FARPROC)NULL, (FARPROC *)&pPeekMessage, (FARPROC)extPeekMessage}, @@ -230,39 +266,13 @@ static HookEntry_Type DesktopHooks[]={ // currently unused, needed for X-Files {HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator }; -FARPROC Remap_user32_ProcAddress(LPCSTR proc, HMODULE hModule) -{ - FARPROC addr; - if (addr=RemapLibrary(proc, hModule, Hooks)) return addr; - if (dxw.dwFlags1 & CLIENTREMAPPING) if (addr=RemapLibrary(proc, hModule, RemapHooks)) return addr; - - if (dxw.dwFlags2 & GDISTRETCHED) - if (addr=RemapLibrary(proc, hModule, ScaledHooks)) return addr; - if (dxw.dwFlags3 & GDIEMULATEDC) - if (addr=RemapLibrary(proc, hModule, EmulateHooks)) return addr; - if (!(dxw.dwFlags2 & GDISTRETCHED) && !(dxw.dwFlags3 & GDIEMULATEDC)) - if (addr=RemapLibrary(proc, hModule, NoGDIHooks)) return addr; - if (dxw.dwFlags1 & (PREVENTMAXIMIZE|FIXWINFRAME|LOCKWINPOS|LOCKWINSTYLE)) - if (addr=RemapLibrary(proc, hModule, WinHooks)) return addr; - if ((dxw.dwFlags1 & (MODIFYMOUSE|SLOWDOWN|KEEPCURSORWITHIN)) || (dxw.dwFlags2 & KEEPCURSORFIXED)) - if (addr=RemapLibrary(proc, hModule, MouseHooks)) return addr; - if (dxw.dwFlags3 & PEEKALLMESSAGES) - if (addr=RemapLibrary(proc, hModule, PeekAllHooks)) return addr; - if((dxw.dwFlags2 & TIMESTRETCH) && (dxw.dwFlags4 & STRETCHTIMERS)) - if (addr=RemapLibrary(proc, hModule, TimeHooks)) return addr; - - return NULL; -} - static char *libname = "user32.dll"; void HookUser32(HMODULE hModule) { HookLibrary(hModule, Hooks, libname); - if (!(dxw.dwFlags2 & GDISTRETCHED) && !(dxw.dwFlags3 & GDIEMULATEDC)) - HookLibrary(hModule, NoGDIHooks, libname); - if (dxw.dwFlags3 & GDIEMULATEDC) HookLibrary(hModule, EmulateHooks, libname); + if (dxw.GDIEmulationMode != GDIMODE_NONE) HookLibrary(hModule, SyscallHooks, libname); if (dxw.dwFlags2 & GDISTRETCHED) HookLibrary(hModule, ScaledHooks, libname); if (dxw.dwFlags1 & CLIENTREMAPPING) HookLibrary(hModule, RemapHooks, libname); @@ -278,13 +288,34 @@ void HookUser32(HMODULE hModule) void HookUser32Init() { HookLibInit(Hooks); + HookLibInit(SyscallHooks); HookLibInit(ScaledHooks); - HookLibInit(EmulateHooks); HookLibInit(RemapHooks); HookLibInit(MouseHooks); HookLibInit(WinHooks); } +FARPROC Remap_user32_ProcAddress(LPCSTR proc, HMODULE hModule) +{ + FARPROC addr; + if (addr=RemapLibrary(proc, hModule, Hooks)) return addr; + if (dxw.dwFlags1 & CLIENTREMAPPING) if (addr=RemapLibrary(proc, hModule, RemapHooks)) return addr; + if (dxw.GDIEmulationMode != GDIMODE_NONE) if(addr=RemapLibrary(proc, hModule, SyscallHooks)) return addr; + + if (dxw.dwFlags2 & GDISTRETCHED) + if (addr=RemapLibrary(proc, hModule, ScaledHooks)) return addr; + if (dxw.dwFlags1 & (PREVENTMAXIMIZE|FIXWINFRAME|LOCKWINPOS|LOCKWINSTYLE)) + if (addr=RemapLibrary(proc, hModule, WinHooks)) return addr; + if ((dxw.dwFlags1 & (MODIFYMOUSE|SLOWDOWN|KEEPCURSORWITHIN)) || (dxw.dwFlags2 & KEEPCURSORFIXED)) + if (addr=RemapLibrary(proc, hModule, MouseHooks)) return addr; + if (dxw.dwFlags3 & PEEKALLMESSAGES) + if (addr=RemapLibrary(proc, hModule, PeekAllHooks)) return addr; + if((dxw.dwFlags2 & TIMESTRETCH) && (dxw.dwFlags4 & STRETCHTIMERS)) + if (addr=RemapLibrary(proc, hModule, TimeHooks)) return addr; + + return NULL; +} + /* ------------------------------------------------------------------------------ */ // auxiliary (static) functions /* ------------------------------------------------------------------------------ */ @@ -601,19 +632,20 @@ static LRESULT WINAPI FixWindowProc(char *ApiName, HWND hwnd, UINT Msg, WPARAM w BOOL WINAPI extInvalidateRect(HWND hwnd, RECT *lpRect, BOOL bErase) { - if(lpRect) - OutTraceDW("InvalidateRect: hwnd=%x rect=(%d,%d)-(%d,%d) erase=%x\n", - hwnd, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, bErase); - else - OutTraceDW("InvalidateRect: hwnd=%x rect=NULL erase=%x\n", - hwnd, bErase); + if(IsTraceDW){ + char sRect[81]; + if(lpRect) sprintf(sRect, "(%d,%d)-(%d,%d)", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + else strcpy(sRect, "NULL"); + OutTrace("InvalidateRect: hwnd=%x rect=%s erase=%x\n", hwnd, sRect, bErase); + } - if(dxw.IsFullScreen()) { + if(dxw.IsFullScreen()) { switch(dxw.GDIEmulationMode){ case GDIMODE_STRETCHED: + case GDIMODE_SHAREDDC: + case GDIMODE_EMULATED: if(lpRect) dxw.MapClient(lpRect); break; - case GDIMODE_EMULATED: default: break; } @@ -957,6 +989,9 @@ BOOL WINAPI extGetCursorPos(LPPOINT lppoint) GetHookInfo()->CursorY=(short)lppoint->y; OutTraceC("GetCursorPos: FIXED pos=(%d,%d)->(%d,%d)\n", prev.x, prev.y, lppoint->x, lppoint->y); + if((dxw.dwFlags1 & HIDEHWCURSOR) && dxw.IsFullScreen()) while((*pShowCursor)(0) >= 0); + if(dxw.dwFlags2 & SHOWHWCURSOR) while((*pShowCursor)(1) < 0); + return res; } @@ -1154,6 +1189,7 @@ BOOL WINAPI extGetWindowRect(HWND hwnd, LPRECT lpRect) return ret; } + int WINAPI extMapWindowPoints(HWND hWndFrom, HWND hWndTo, LPPOINT lpPoints, UINT cPoints) { UINT pi; @@ -1180,14 +1216,22 @@ int WINAPI extMapWindowPoints(HWND hWndFrom, HWND hWndTo, LPPOINT lpPoints, UINT ret=(*pMapWindowPoints)(hWndFrom, hWndTo, lpPoints, cPoints); // v2.03.16: now must scale every point (fixes "NBA Live 99") // v2.03.18: in some cases it should not! "New Your Race"... - for(pi=0; pilpszClassName, lpwcx->style, ExplainStyle(lpwcx->style), lpwcx->lpfnWndProc, lpwcx->cbClsExtra, lpwcx->cbWndExtra, lpwcx->hInstance); - return (*pRegisterClassExA)(lpwcx); + ret = (*pRegisterClassExA)(lpwcx); + OutTraceDW("RegisterClassExA: atom=%x\n", ret); + return ret; } -ATOM WINAPI extRegisterClassA(WNDCLASS *lpwcx) +ATOM WINAPI extRegisterClassA(WNDCLASSA *lpwcx) { + ATOM ret; // referenced by Syberia, together with RegisterClassExA - OutTraceDW("RegisterClass: PROXED ClassName=%s style=%x(%s) WndProc=%x cbClsExtra=%d cbWndExtra=%d hInstance=%x\n", + OutTraceDW("RegisterClassA: PROXED ClassName=%s style=%x(%s) WndProc=%x cbClsExtra=%d cbWndExtra=%d hInstance=%x\n", lpwcx->lpszClassName, lpwcx->style, ExplainStyle(lpwcx->style), lpwcx->lpfnWndProc, lpwcx->cbClsExtra, lpwcx->cbWndExtra, lpwcx->hInstance); - return (*pRegisterClassA)(lpwcx); + ret = (*pRegisterClassA)(lpwcx); + OutTraceDW("RegisterClassA: atom=%x\n", ret); + return ret; +} + +ATOM WINAPI extRegisterClassExW(WNDCLASSEXW *lpwcx) +{ + ATOM ret; + OutTraceDW("RegisterClassExW: PROXED ClassName=%ls style=%x(%s) WndProc=%x cbClsExtra=%d cbWndExtra=%d hInstance=%x\n", + lpwcx->lpszClassName, lpwcx->style, ExplainStyle(lpwcx->style), lpwcx->lpfnWndProc, lpwcx->cbClsExtra, lpwcx->cbWndExtra, lpwcx->hInstance); + ret = (*pRegisterClassExW)(lpwcx); + OutTraceDW("RegisterClassExW: atom=%x\n", ret); + return ret; +} + +ATOM WINAPI extRegisterClassW(WNDCLASSW *lpwcx) +{ + ATOM ret; + OutTraceDW("RegisterClassW: PROXED ClassName=%ls style=%x(%s) WndProc=%x cbClsExtra=%d cbWndExtra=%d hInstance=%x\n", + lpwcx->lpszClassName, lpwcx->style, ExplainStyle(lpwcx->style), lpwcx->lpfnWndProc, lpwcx->cbClsExtra, lpwcx->cbWndExtra, lpwcx->hInstance); + ret = (*pRegisterClassW)(lpwcx); + OutTraceDW("RegisterClassW: atom=%x\n", ret); + return ret; } static void HookChildWndProc(HWND hwnd, DWORD dwStyle, LPCTSTR ApiName) @@ -1302,7 +1372,7 @@ static void HookChildWndProc(HWND hwnd, DWORD dwStyle, LPCTSTR ApiName) (pWindowProc == extDialogWindowProc)){ // avoid recursions HWND Father; WNDPROC pFatherProc; - Father=GetParent(hwnd); + Father=(*pGetParent)(hwnd); pFatherProc=dxwws.GetProc(Father); OutTraceDW("%s: WndProc=%s father=%x WndProc=%x\n", ApiName, (pWindowProc == extWindowProc) ? "extWindowProc" : ((pWindowProc == extChildWindowProc) ? "extChildWindowProc" : "extDialogWindowProc"), @@ -1323,6 +1393,41 @@ static void HookChildWndProc(HWND hwnd, DWORD dwStyle, LPCTSTR ApiName) HWND hControlParentWnd = NULL; +// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms632679%28v=vs.85%29.aspx + +static BOOL IsFullscreenWindow( + void *lpClassName, + DWORD dwStyle, + DWORD dwExStyle, + HWND hWndParent, + int x, + int y, + int nWidth, + int nHeight) +{ + if (dwExStyle & WS_EX_CONTROLPARENT) return FALSE; // "Diablo" fix + if ((dwStyle & WS_CHILD) && (!dxw.IsDesktop(hWndParent))) return FALSE; // Diablo fix + // if maximized. + if(dwStyle & WS_MAXIMIZE) return TRUE; + // go through here only when WS_CHILD of desktop window + if((x == CW_USEDEFAULT) && (dwStyle & (WS_POPUP|WS_CHILD))) x = y = 0; + if(nWidth == CW_USEDEFAULT){ + if (dwStyle & (WS_POPUP|WS_CHILD)) nWidth = nHeight = 0; + else nWidth = dxw.GetScreenWidth() - x; + } + // msdn undocumented case: x,y=(-1000, CW_USEDEFAULT) w,h=(CW_USEDEFAULT,CW_USEDEFAULT) in "Imperialism" + if(nHeight == CW_USEDEFAULT){ + y = 0; + nHeight = dxw.GetScreenHeight(); + } + // if bigger than screen ... + if((x<=0)&& + (y<=0)&& + (nWidth>=(int)dxw.GetScreenWidth())&& + (nHeight>=(int)dxw.GetScreenHeight())) return TRUE; + return FALSE; +} + static HWND WINAPI extCreateWindowCommon( LPCTSTR ApiName, BOOL WideChar, @@ -1380,33 +1485,15 @@ static HWND WINAPI extCreateWindowCommon( // main win was 640x480 only! // v2.02.13: if it's a WS_CHILD window, don't reposition the x,y, placement for BIG win. // v2.02.30: fix (Fable - lost chapters) Fable creates a bigger win with negative x,y coordinates. -if ( - ( - ((x<=0)&&(y<=0)) - || - ((x==CW_USEDEFAULT)&&(y==CW_USEDEFAULT)) - ) - && - ( - ((nWidth>=(int)dxw.GetScreenWidth())&&(nHeight>=(int)dxw.GetScreenHeight())) - || - ((nWidth==CW_USEDEFAULT)&&(nHeight==CW_USEDEFAULT)) // good for Imperialism, but is it general? - ) - && - !(dwExStyle & WS_EX_CONTROLPARENT) // Diablo fix - && - !(dwStyle & WS_CHILD) // Diablo fix - ) - { + // v2.03.53: revised code, logic moved to IsFullscreenWindow + + if(IsFullscreenWindow(lpClassName, dwStyle, dwExStyle, hWndParent, x, y, nWidth, nHeight)){ RECT screen; POINT upleft = {0,0}; - // v2.02.30: fix (Fable - lost chapters) - if(nWidth==CW_USEDEFAULT) nWidth=dxw.GetScreenWidth(); - if(nHeight==CW_USEDEFAULT) nHeight=dxw.GetScreenHeight(); - // update virtual screen size if it has grown dxw.SetScreenSize(nWidth, nHeight); + // inserted some checks here, since the main window could be destroyed // or minimized (see "Jedi Outcast") so that you may get a dangerous // zero size. In this case, better renew the hWnd assignement and its coordinates. @@ -1427,12 +1514,8 @@ if ( OutTraceDW("%s: fixed BIG win pos=(%d,%d) size=(%d,%d)\n", ApiName, x, y, nWidth, nHeight); } else { - // invalid parent coordinates: use initial placement, but leave the size. - // should also fix the window style and compensate for borders here? - // if (!(dwStyle & WS_CHILD)){ // commented out: can't be! see if condition - x=dxw.iPosX; - y=dxw.iPosY; - //} + x=dxw.iPosX; + y=dxw.iPosY; nWidth=dxw.iSizX; nHeight=dxw.iSizY; OutTraceDW("%s: renewed BIG win pos=(%d,%d) size=(%d,%d)\n", ApiName, x, y, nWidth, nHeight); @@ -1711,7 +1794,12 @@ static int HandleRect(char *ApiName, void *pFun, HDC hdc, const RECT *lprc, HBRU memcpy(&rc, lprc, sizeof(rc)); - if(dxw.IsRealDesktop(WindowFromDC(hdc))) { + // Be careful: when you call CreateCompatibleDC with NULL DC, it is created a memory DC + // with same characteristics as desktop. That would return true from the call to + // dxw.IsRealDesktop(WindowFromDC(hdc)) because WindowFromDC(hdc) is null. + // So, it's fundamental to check also the hdc type (OBJ_DC is a window's DC) + + if((dxw.IsRealDesktop(WindowFromDC(hdc)) && (OBJ_DC == (*pGetObjectType)(hdc)))) { HWND VirtualDesktop; VirtualDesktop=dxw.GethWnd(); if(VirtualDesktop==NULL){ @@ -1722,7 +1810,28 @@ static int HandleRect(char *ApiName, void *pFun, HDC hdc, const RECT *lprc, HBRU hdc=(*pGDIGetDC)(dxw.GethWnd()); } - if(!dxw.IsFullScreen()) { + if(dxw.IsToRemap(hdc)) { + if(rc.left < 0) rc.left = 0; + if(rc.top < 0) rc.top = 0; + if((DWORD)rc.right > dxw.GetScreenWidth()) rc.right = dxw.GetScreenWidth(); + if((DWORD)rc.bottom > dxw.GetScreenHeight()) rc.bottom = dxw.GetScreenHeight(); + + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + res=(*(FillRect_Type)pFun)(sdc.GetHdc(), &rc, hbr); + sdc.PutPrimaryDC(hdc, TRUE, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top); + return res; + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&rc); + OutTraceDW("%s: fixed rect=(%d,%d)-(%d,%d)\n", ApiName, rc.left, rc.top, rc.right, rc.bottom); + break; + default: + break; + } + } + else { // when not in fullscreen mode, just proxy the call // but check coordinates: some games may use excessive coordinates: see "Premier Manager 98" RECT client; @@ -1735,18 +1844,7 @@ static int HandleRect(char *ApiName, void *pFun, HDC hdc, const RECT *lprc, HBRU if(rc.bottom > client.bottom) rc.bottom=client.bottom; OutTraceDW("%s: remapped hdc from hwnd=%x to rect=(%d,%d)-(%d,%d)\n", ApiName, hwnd, rc.left, rc.top, rc.right, rc.bottom); } - else { - if(OBJ_DC == GetObjectType(hdc)){ - if(rc.left < 0) rc.left = 0; - if(rc.top < 0) rc.top = 0; - if((DWORD)rc.right > dxw.GetScreenWidth()) rc.right = dxw.GetScreenWidth(); - if((DWORD)rc.bottom > dxw.GetScreenHeight()) rc.bottom = dxw.GetScreenHeight(); - dxw.MapClient(&rc); - OutTraceDW("%s: fixed rect=(%d,%d)-(%d,%d)\n", ApiName, rc.left, rc.top, rc.right, rc.bottom); - } - } - //res=(*pFillRect)(hdc, &rc, hbr); res=(*(FillRect_Type)pFun)(hdc, &rc, hbr); return res; } @@ -1761,6 +1859,55 @@ int WINAPI extFrameRect(HDC hdc, const RECT *lprc, HBRUSH hbr) return HandleRect("FramelRect", (void *)pFrameRect, hdc, lprc, hbr); } +BOOL WINAPI extInvertRect(HDC hdc, const RECT *lprc) +{ + int res; + RECT rc; + OutTraceDW("InvertRect: hdc=%x rect=(%d,%d)-(%d,%d)\n", hdc, lprc->left, lprc->top, lprc->right, lprc->bottom); + + memcpy(&rc, lprc, sizeof(rc)); + + if(dxw.IsToRemap(hdc)) { + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + res=(*pInvertRect)(sdc.GetHdc(), &rc); + sdc.PutPrimaryDC(hdc, TRUE, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top); + return res; + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&rc); + OutTraceDW("InvertRect: fixed rect=(%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom); + break; + default: + break; + } + } + + res=(*pInvertRect)(hdc, &rc); + return res; +} + +int WINAPI extValidateRect(HWND hwnd, const RECT *lprc) +{ + int res; + RECT rc; + + OutTraceDW("ValidateRect: hwnd=%x rect=(%d,%d)-(%d,%d)\n", + hwnd, lprc->left, lprc->top, lprc->right, lprc->bottom); + + memcpy(&rc, lprc, sizeof(rc)); + + if(dxw.IsFullScreen()) { + if(dxw.IsRealDesktop(hwnd)) hwnd=dxw.GethWnd(); + dxw.MapClient(&rc); + OutTraceDW("ValidateRect: fixed rect=(%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom); + } + + res=(*pValidateRect)(hwnd, &rc); + return res; +} + BOOL WINAPI extClipCursor(RECT *lpRectArg) { // reference: hooking and setting ClipCursor is mandatori in "Emergency: Fighters for Life" @@ -2003,18 +2150,15 @@ static HDC WINAPI sGetDC(HWND hwnd, char *ApiName) lochwnd=dxw.GethWnd(); } - if(bFlippedDC) { - ret = dxw.AcquireSharedDC(hwnd); - if(ret) return ret; - } - switch(dxw.GDIEmulationMode){ - case GDIMODE_STRETCHED: - ret=(*pGDIGetDC)(lochwnd); - break; case GDIMODE_EMULATED: ret=dxw.AcquireEmulatedDC(lochwnd); break; + case GDIMODE_STRETCHED: + case GDIMODE_SHAREDDC: + default: + ret=(*pGDIGetDC)(lochwnd); + break; } if(ret){ @@ -2073,15 +2217,15 @@ int WINAPI extGDIReleaseDC(HWND hwnd, HDC hDC) if (dxw.IsRealDesktop(hwnd)) hwnd=dxw.GethWnd(); if(hwnd == 0) return(TRUE); - if(bFlippedDC && (hDC == hFlippedDC)) return dxw.ReleaseSharedDC(hwnd, hDC); - switch(dxw.GDIEmulationMode){ - case GDIMODE_STRETCHED: - res=(*pGDIReleaseDC)(hwnd, hDC); - break; case GDIMODE_EMULATED: res=dxw.ReleaseEmulatedDC(hwnd); break; + case GDIMODE_STRETCHED: + case GDIMODE_SHAREDDC: + default: + res=(*pGDIReleaseDC)(hwnd, hDC); + break; } if (!res) OutTraceE("GDI.ReleaseDC ERROR: err=%d at %d\n", GetLastError(), __LINE__); @@ -2102,27 +2246,29 @@ HDC WINAPI extBeginPaint(HWND hwnd, LPPAINTSTRUCT lpPaint) // if not in fullscreen mode, that's all! if(!dxw.IsFullScreen()) return hdc; - - if(bFlippedDC) { - hdc = dxw.AcquireSharedDC(hwnd); - } - else { - switch(dxw.GDIEmulationMode){ - case GDIMODE_STRETCHED: - // on CLIENTREMAPPING, resize the paint area to virtual screen size - //if(dxw.dwFlags1 & CLIENTREMAPPING) lpPaint->rcPaint=dxw.GetScreenRect(); - if(dxw.dwFlags1 & CLIENTREMAPPING) dxw.UnmapClient(&(lpPaint->rcPaint)); - break; - case GDIMODE_EMULATED: - HDC EmuHDC; - EmuHDC = dxw.AcquireEmulatedDC(hwnd); - lpPaint->hdc=EmuHDC; - hdc = EmuHDC; - break; - } + switch(dxw.GDIEmulationMode){ + case GDIMODE_STRETCHED: + if(dxw.dwFlags1 & CLIENTREMAPPING) dxw.UnmapClient(&(RECT)(lpPaint->rcPaint)); + break; + case GDIMODE_EMULATED: + HDC EmuHDC; + EmuHDC = dxw.AcquireEmulatedDC(hwnd); + lpPaint->hdc=EmuHDC; + hdc = EmuHDC; + break; + case GDIMODE_SHAREDDC: +#if 0 + sdc.GetPrimaryDC(hdc); + lpPaint->hdc = sdc.GetHdc(); + (*pBeginPaint)(hwnd, lpPaint); + lpPaint->hdc = hdc; + sdc.PutPrimaryDC(hdc, FALSE); +#endif + break; + default: + break; } - OutTraceDW("GDI.BeginPaint: hdc=%x rcPaint=(%d,%d)-(%d,%d)\n", hdc, lpPaint->rcPaint.left, lpPaint->rcPaint.top, lpPaint->rcPaint.right, lpPaint->rcPaint.bottom); return hdc; @@ -2136,21 +2282,33 @@ BOOL WINAPI extEndPaint(HWND hwnd, const PAINTSTRUCT *lpPaint) hwnd, lpPaint, lpPaint->hdc, lpPaint->rcPaint.left, lpPaint->rcPaint.top, lpPaint->rcPaint.right, lpPaint->rcPaint.bottom); // if not fullscreen or not desktop win, just proxy the call - if(!dxw.IsFullScreen() || !dxw.Windowize){ + if(!dxw.IsFullScreen()){ ret=(*pEndPaint)(hwnd, lpPaint); return ret; } // avoid access to real desktop if(dxw.IsRealDesktop(hwnd)) hwnd=dxw.GethWnd(); - switch(dxw.GDIEmulationMode){ - case GDIMODE_STRETCHED: - ret=(*pEndPaint)(hwnd, lpPaint); - break; case GDIMODE_EMULATED: ret=dxw.ReleaseEmulatedDC(hwnd); break; + case GDIMODE_SHAREDDC: +#if 1 + if(lpPaint) dxw.MapClient((LPRECT)&(lpPaint->rcPaint)); + ret=(*pEndPaint)(hwnd, lpPaint); +#else + PAINTSTRUCT Paint; + Paint = *lpPaint; + Paint.hdc = sdc.GetHdc(); + (*pEndPaint)(hwnd, &Paint); + if(lpPaint) dxw.MapClient((LPRECT)&(lpPaint->rcPaint)); + ret=(*pEndPaint)(hwnd, lpPaint); +#endif + break; + default: + ret=(*pEndPaint)(hwnd, lpPaint); + break; } if(ret){ @@ -2318,9 +2476,53 @@ BOOL WINAPI extDrawFocusRect(HDC hDC, const RECT *lprc) return TRUE; } -BOOL WINAPI extScrollDC(HDC hDC, int dx, int dy, const RECT *lprcScroll, const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate) +BOOL WINAPI extScrollDC(HDC hdc, int dx, int dy, const RECT *lprcScroll, const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate) { - return TRUE; + BOOL res; + if(IsTraceDW){ + char sRect[81]; + if(lprcScroll) sprintf(sRect, "(%d,%d)-(%d,%d)", lprcScroll->left, lprcScroll->top, lprcScroll->right, lprcScroll->bottom); + else strcpy(sRect, "NULL"); + char sClip[81]; + if(lprcClip) sprintf(sClip, "(%d,%d)-(%d,%d)", lprcClip->left, lprcClip->top, lprcClip->right, lprcClip->bottom); + else strcpy(sClip, "NULL"); + OutTraceDW("ScrollDC: hdc=%x dxy=(%d,%d) scrollrect=%s cliprect=%s hrgn=%x\n", + hdc, dx, dy, sRect, sClip, hrgnUpdate); + } + + if(dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + res=(*pScrollDC)(sdc.GetHdc(), dx, dy, lprcScroll, lprcClip, hrgnUpdate, lprcUpdate); + sdc.PutPrimaryDC(hdc, TRUE, lprcUpdate->left, lprcUpdate->top, lprcUpdate->right-lprcUpdate->left, lprcUpdate->bottom-lprcUpdate->top); + return res; + break; + case GDIMODE_EMULATED: +#if 0 + // not working with 688(I) sonar !!! + if(dxw.IsVirtual(hdc)){ + RECT rcScroll, rcClip; + if(lprcScroll) { + rcScroll = *lprcScroll; + OffsetRect(&rcScroll, dxw.VirtualOffsetX, dxw.VirtualOffsetY); + } + if(lprcClip) { + rcClip = *lprcClip; + OffsetRect(&rcClip, dxw.VirtualOffsetX, dxw.VirtualOffsetY); + } + res=(*pScrollDC)(hdc, dx, dy, &rcScroll, &rcClip, hrgnUpdate, lprcUpdate); + return res; + } +#endif + break; + default: + break; + } + } + + res=(*pScrollDC)(hdc, dx, dy, lprcScroll, lprcClip, hrgnUpdate, lprcUpdate); + return res; } HWND WINAPI extGetTopWindow(HWND hwnd) @@ -2339,15 +2541,66 @@ LONG WINAPI extTabbedTextOutA(HDC hdc, int X, int Y, LPCTSTR lpString, int nCoun OutTraceDW("TabbedTextOut: hdc=%x xy=(%d,%d) nCount=%d nTP=%d nTOS=%d str=(%d)\"%s\"\n", hdc, X, Y, nCount, nTabPositions, nTabOrigin, lpString); - if (dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ - dxw.MapClient(&X, &Y); - OutTraceDW("TextOut: fixed dest=(%d,%d)\n", X, Y); + if(dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + res=(*pTabbedTextOutA)(sdc.GetHdc(), X, Y, lpString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin); + sdc.PutPrimaryDC(hdc, TRUE); + return res; + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&X, &Y); + break; + case GDIMODE_EMULATED: + if(dxw.IsVirtual(hdc)){ + X+=dxw.VirtualOffsetX; + Y+=dxw.VirtualOffsetY; + } + break; + default: + break; + } + OutTraceDW("TabbedTextOutA: fixed dest=(%d,%d)\n", X, Y); } res=(*pTabbedTextOutA)(hdc, X, Y, lpString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin); return res; } +LONG WINAPI extTabbedTextOutW(HDC hdc, int X, int Y, LPCWSTR lpString, int nCount, int nTabPositions, const LPINT lpnTabStopPositions, int nTabOrigin) +{ + BOOL res; + OutTraceDW("TabbedTextOutW: hdc=%x xy=(%d,%d) nCount=%d nTP=%d nTOS=%d str=(%d)\"%ls\"\n", + hdc, X, Y, nCount, nTabPositions, nTabOrigin, lpString); + + if(dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + res=(*pTabbedTextOutW)(sdc.GetHdc(), X, Y, lpString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin); + sdc.PutPrimaryDC(hdc, TRUE); + return res; + break; + case GDIMODE_STRETCHED: + dxw.MapClient(&X, &Y); + break; + case GDIMODE_EMULATED: + if(dxw.IsVirtual(hdc)){ + X+=dxw.VirtualOffsetX; + Y+=dxw.VirtualOffsetY; + } + break; + default: + break; + } + OutTraceDW("TabbedTextOutW: fixed dest=(%d,%d)\n", X, Y); + } + + res=(*pTabbedTextOutW)(hdc, X, Y, lpString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin); + return res; +} + BOOL WINAPI extDestroyWindow(HWND hWnd) { // v2.02.43: "Empire Earth" builds test surfaces that must be destroyed! @@ -2416,37 +2669,47 @@ BOOL gFixed; int WINAPI extDrawTextA(HDC hdc, LPCTSTR lpchText, int nCount, LPRECT lpRect, UINT uFormat) { int ret; - BOOL MustScale; - OutTraceDW("DrawText: hdc=%x rect=(%d,%d)-(%d,%d) Format=%x(%s) Text=(%d)\"%s\"\n", + OutTraceDW("DrawTextA: hdc=%x rect=(%d,%d)-(%d,%d) Format=%x(%s) Text=(%d)\"%s\"\n", hdc, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, uFormat, ExplainDTFormat(uFormat), nCount, lpchText); + gFixed = TRUE; // semaphore to avoid multiple scaling with HOT patching + if(dxw.IsToRemap(hdc)){ - MustScale = dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc)); - if (MustScale){ - dxw.MapClient((RECT *)lpRect); - OutTraceDW("DrawText: fixed rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pDrawTextA)(sdc.GetHdc(), lpchText, nCount, lpRect, uFormat); + if(nCount) + sdc.PutPrimaryDC(hdc, TRUE, lpRect->left, lpRect->top, lpRect->right-lpRect->left, lpRect->bottom-lpRect->top); + else + sdc.PutPrimaryDC(hdc, FALSE); // Diablo makes a DrawText of nuull string in the intro ... + return ret; + break; + case GDIMODE_STRETCHED: + dxw.MapClient((RECT *)lpRect); + OutTraceDW("DrawTextA: fixed rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + ret=(*pDrawTextA)(hdc, lpchText, nCount, lpRect, uFormat); + dxw.UnmapClient((RECT *)lpRect); + OutTraceDW("DrawTextA: fixed output rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + break; + default: + ret=(*pDrawTextA)(hdc, lpchText, nCount, lpRect, uFormat); + break; + } + } + else { + ret=(*pDrawTextA)(hdc, lpchText, nCount, lpRect, uFormat); } - - gFixed = TRUE; - ret=(*pDrawText)(hdc, lpchText, nCount, lpRect, uFormat); gFixed = FALSE; // if nCount is zero, DrawRect returns 0 as text heigth, but this is not an error! (ref. "Imperialism II") - if(nCount && !ret) OutTraceE("DrawText: ERROR ret=%x err=%d\n", ret, GetLastError()); - - if (MustScale){ - dxw.UnmapClient((RECT *)lpRect); - OutTraceDW("DrawText: fixed output rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); - } - + if(nCount && !ret) OutTraceE("DrawTextA: ERROR ret=%x err=%d\n", ret, GetLastError()); return ret; } int WINAPI extDrawTextExA(HDC hdc, LPTSTR lpchText, int nCount, LPRECT lpRect, UINT dwDTFormat, LPDRAWTEXTPARAMS lpDTParams) { int ret; - BOOL MustScale; - - OutTraceDW("DrawTextEx: hdc=%x rect=(%d,%d)-(%d,%d) DTFormat=%x Text=(%d)\"%s\"\n", + OutTraceDW("DrawTextExA: hdc=%x rect=(%d,%d)-(%d,%d) DTFormat=%x Text=(%d)\"%s\"\n", hdc, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, dwDTFormat, nCount, lpchText); if (IsDebug){ if(lpDTParams) @@ -2457,23 +2720,117 @@ int WINAPI extDrawTextExA(HDC hdc, LPTSTR lpchText, int nCount, LPRECT lpRect, U OutTrace("DTParams: NULL\n"); } - MustScale = dxw.IsFullScreen() && (OBJ_DC == GetObjectType(hdc)); - - if (MustScale){ - dxw.MapClient((RECT *)lpRect); - OutTraceDW("DrawTextEx: fixed rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + gFixed = TRUE; // semaphore to avoid multiple scaling with HOT patching + if(dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pDrawTextExA)(sdc.GetHdc(), lpchText, nCount, lpRect, dwDTFormat, lpDTParams); + sdc.PutPrimaryDC(hdc, TRUE, lpRect->left, lpRect->top, lpRect->right-lpRect->left, lpRect->bottom-lpRect->top); + return ret; + break; + case GDIMODE_STRETCHED: + dxw.MapClient((RECT *)lpRect); + OutTraceDW("DrawTextA: fixed rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + ret=(*pDrawTextExA)(hdc, lpchText, nCount, lpRect, dwDTFormat, lpDTParams); + dxw.UnmapClient((RECT *)lpRect); + OutTraceDW("DrawTextA: fixed output rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + break; + default: + ret=(*pDrawTextExA)(hdc, lpchText, nCount, lpRect, dwDTFormat, lpDTParams); + break; + } } + else { + ret=(*pDrawTextExA)(hdc, lpchText, nCount, lpRect, dwDTFormat, lpDTParams); + } + gFixed = FALSE; - gFixed = TRUE; - ret=(*pDrawTextEx)(hdc, lpchText, nCount, lpRect, dwDTFormat, lpDTParams); - gFixed = FALSE; - if(nCount && !ret) OutTraceE("DrawTextEx: ERROR ret=%x err=%d\n", ret, GetLastError()); + // if nCount is zero, DrawRect returns 0 as text heigth, but this is not an error! (ref. "Imperialism II") + if(nCount && !ret) OutTraceE("DrawTextA: ERROR ret=%x err=%d\n", ret, GetLastError()); + return ret; +} - if (MustScale){ - dxw.UnmapClient((RECT *)lpRect); - OutTraceDW("DrawTextEx: fixed output rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); +int WINAPI extDrawTextW(HDC hdc, LPCWSTR lpchText, int nCount, LPRECT lpRect, UINT uFormat) +{ + int ret; + OutTraceDW("DrawTextW: hdc=%x rect=(%d,%d)-(%d,%d) Format=%x(%s) Text=(%d)\"%ls\"\n", + hdc, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, uFormat, ExplainDTFormat(uFormat), nCount, lpchText); + + gFixed = TRUE; // semaphore to avoid multiple scaling with HOT patching + if(dxw.IsToRemap(hdc)){ + + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pDrawTextW)(sdc.GetHdc(), lpchText, nCount, lpRect, uFormat); + sdc.PutPrimaryDC(hdc, TRUE, lpRect->left, lpRect->top, lpRect->right-lpRect->left, lpRect->bottom-lpRect->top); + return ret; + break; + case GDIMODE_STRETCHED: + dxw.MapClient((RECT *)lpRect); + OutTraceDW("DrawTextW: fixed rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + ret=(*pDrawTextW)(hdc, lpchText, nCount, lpRect, uFormat); + dxw.UnmapClient((RECT *)lpRect); + OutTraceDW("DrawTextW: fixed output rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + break; + default: + ret=(*pDrawTextW)(hdc, lpchText, nCount, lpRect, uFormat); + break; + } + } + else { + ret=(*pDrawTextW)(hdc, lpchText, nCount, lpRect, uFormat); + } + gFixed = FALSE; + + // if nCount is zero, DrawRect returns 0 as text heigth, but this is not an error! (ref. "Imperialism II") + if(nCount && !ret) OutTraceE("DrawTextW: ERROR ret=%x err=%d\n", ret, GetLastError()); + return ret; +} + +int WINAPI extDrawTextExW(HDC hdc, LPCWSTR lpchText, int nCount, LPRECT lpRect, UINT dwDTFormat, LPDRAWTEXTPARAMS lpDTParams) +{ + int ret; + OutTraceDW("DrawTextExW: hdc=%x rect=(%d,%d)-(%d,%d) DTFormat=%x Text=(%d)\"%ls\"\n", + hdc, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, dwDTFormat, nCount, lpchText); + if (IsDebug){ + if(lpDTParams) + OutTrace("DTParams: size=%d (L,R)margins=(%d,%d) TabLength=%d lDrawn=%d\n", + lpDTParams->cbSize, lpDTParams->iLeftMargin, lpDTParams->iRightMargin, + lpDTParams->iTabLength, lpDTParams->uiLengthDrawn); + else + OutTrace("DTParams: NULL\n"); } + gFixed = TRUE; // semaphore to avoid multiple scaling with HOT patching + if(dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pDrawTextExW)(sdc.GetHdc(), lpchText, nCount, lpRect, dwDTFormat, lpDTParams); + sdc.PutPrimaryDC(hdc, TRUE, lpRect->left, lpRect->top, lpRect->right-lpRect->left, lpRect->bottom-lpRect->top); + return ret; + break; + case GDIMODE_STRETCHED: + dxw.MapClient((RECT *)lpRect); + OutTraceDW("DrawTextExW: fixed rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + ret=(*pDrawTextExW)(hdc, lpchText, nCount, lpRect, dwDTFormat, lpDTParams); + dxw.UnmapClient((RECT *)lpRect); + OutTraceDW("DrawTextExW: fixed output rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + break; + default: + ret=(*pDrawTextExW)(hdc, lpchText, nCount, lpRect, dwDTFormat, lpDTParams); + break; + } + } + else { + ret=(*pDrawTextExW)(hdc, lpchText, nCount, lpRect, dwDTFormat, lpDTParams); + } + gFixed = FALSE; + + // if nCount is zero, DrawRect returns 0 as text heigth, but this is not an error! (ref. "Imperialism II") + if(nCount && !ret) OutTraceE("DrawTextExW: ERROR ret=%x err=%d\n", ret, GetLastError()); return ret; } @@ -2521,8 +2878,27 @@ BOOL WINAPI extUpdateWindow(HWND hwnd) BOOL WINAPI extRedrawWindow(HWND hWnd, const RECT *lprcUpdate, HRGN hrgnUpdate, UINT flags) { + RECT rcUpdate; + BOOL ret; + OutTraceDW("RedrawWindow: hwnd=%x flags=%x\n", hWnd, flags); - return (*pRedrawWindow)(hWnd, lprcUpdate, hrgnUpdate, flags); + + rcUpdate = *lprcUpdate; + // avoid redrawing the whole desktop + if(dxw.Windowize && dxw.IsRealDesktop(hWnd)) hWnd=dxw.GethWnd(); + if(dxw.IsFullScreen()){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_STRETCHED: + rcUpdate = dxw.MapClientRect((LPRECT)lprcUpdate); + break; + default: + break; + } + } + + ret = (*pRedrawWindow)(hWnd, &rcUpdate, hrgnUpdate, flags); + if(ret) OutTraceE("RedrawWindow ERROR: err=%d\n", GetLastError()); + return ret; } @@ -2808,7 +3184,7 @@ int WINAPI extGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase) OutTraceDW("GetUpdateRgn: hwnd=%x hrgn=%x erase=%x regionType=%x(%s)\n", hWnd, hRgn, bErase, regionType, ExplainRegionType(regionType)); - if(dxw.Windowize && dxw.IsFullScreen()){ + if(dxw.IsFullScreen()){ if(regionType == SIMPLEREGION){ RECT rc; if(!pGetRgnBox) pGetRgnBox=GetRgnBox; @@ -2851,7 +3227,7 @@ UINT WINAPI extGetDIBColorTable(HDC hdc, UINT uStartIndex, UINT cEntries, RGBQUA UINT ret; OutTraceDW("GetDIBColorTable: hdc=%x start=%d entries=%d\n", hdc, uStartIndex, cEntries); - //if((OBJ_DC == GetObjectType(hdc)) && (dxw.dwFlags1 & EMULATESURFACE)){ + //if((OBJ_DC == (*pGetObjectType)(hdc)) && (dxw.dwFlags1 & EMULATESURFACE)){ // //extern PALETTEENTRY PalEntries[256]; // extern DWORD *PaletteEntries; // if((uStartIndex+cEntries) > 256) cEntries = 256 - uStartIndex; @@ -3005,6 +3381,9 @@ HHOOK WINAPI extSetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWOR // v2.03.39: "One Must Fall Battlegrounds" keyboard fix if((idHook == WH_KEYBOARD) && (dwThreadId == NULL)) dwThreadId = GetCurrentThreadId(); + // v2.03.54: disable the disable Alt-Tab fix + if((dxw.dwFlags7 & DISABLEDISABLEALTTAB) && (idHook == WH_KEYBOARD_LL)) return NULL; + ret=(*pSetWindowsHookEx)(idHook, lpfn, hMod, dwThreadId); return ret; @@ -3071,7 +3450,7 @@ BOOL WINAPI extIsZoomed(HWND hWnd) { BOOL ret; ret = (*pIsZoomed)(hWnd); - OutTrace("IsZoomed: hwnd=%x ret=%x\n", hWnd, ret); + OutTraceDW("IsZoomed: hwnd=%x ret=%x\n", hWnd, ret); //if(dxw.IsFullScreen()) ret = FALSE; return ret; } @@ -3080,7 +3459,168 @@ BOOL WINAPI extIsIconic(HWND hWnd) { BOOL ret; ret = (*pIsIconic)(hWnd); - OutTrace("IsIconic: hwnd=%x ret=%x\n", hWnd, ret); + OutTraceDW("IsIconic: hwnd=%x ret=%x\n", hWnd, ret); //return FALSE; return ret; } + +BOOL extScrollWindow(HWND hWnd, int XAmount, int YAmount, const RECT *lpRect, const RECT *lpClipRect) +{ + RECT Rect, ClipRect; + BOOL res; + + OutTraceDW("ScrollWindow: hwnd=%x amount=(%d,%d) rect=(%d,%d)-(%d,%d) clip=(%d,%d)-(%d,%d)\n", + hWnd, XAmount, YAmount, + lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, + lpClipRect->left, lpClipRect->top, lpClipRect->right, lpClipRect->bottom); + + Rect = *lpRect; + ClipRect = *lpClipRect; + if(dxw.Windowize && dxw.IsFullScreen()){ + dxw.MapClient(&XAmount, &YAmount); + dxw.MapClient(&Rect); + dxw.MapClient(&ClipRect); + } + + res=(*pScrollWindow)(hWnd, XAmount, YAmount, (const RECT *)&Rect, (const RECT *)&ClipRect); + if(!res) OutTraceE("ScrollWindow ERROR: err=%d\n", GetLastError()); + return res; +} + +#if 0 +// avoid invalidating whole desktop!!! +BOOL InvalidateRgn( + _In_ HWND hWnd, + _In_ HRGN hRgn, + _In_ BOOL bErase +); + +#endif + +HWND WINAPI extGetParent(HWND hWnd) +{ + // Beware: can cause recursion on HOT PATCH mode + HWND ret; + + ret = (*pGetParent)(hWnd); + OutTraceB("GetParent: hwnd=%x ret=%x\n", hWnd, ret); + + if(dxw.IsFullScreen()){ + if(ret == dxw.GethWnd()) { + OutTraceB("GetParent: setting desktop reached\n"); + ret = 0; // simulate reaching the desktop + } + } + + return ret; +} + +BOOL WINAPI extInvalidateRgn(HWND hWnd, HRGN hRgn, BOOL bErase) +{ + OutTraceDW("InvalidateRgn: hwnd=%x hrgn=%x erase=%x\n", hWnd, hRgn, bErase); + + if(dxw.IsFullScreen()){ + if (dxw.IsRealDesktop(hWnd) && bErase) return true; + } + + return (*pInvalidateRgn)(hWnd, hRgn, bErase); +} + +BOOL WINAPI extDrawIcon(HDC hdc, int X, int Y, HICON hIcon) +{ + BOOL ret; + OutTraceDW("DrawIcon: hdcdest=%x pos=(%d,%d) hicon=%x\n", hdc, X, Y, hIcon); + if(dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_STRETCHED: + dxw.MapClient(&X, &Y); + OutTraceDW("OffsetRgn: fixed STRETCHED pos=(%d,%d)\n", X, Y); + break; + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pDrawIcon)(sdc.GetHdc(), X, Y, hIcon); + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + default: + break; + } + } + + ret = (*pDrawIcon)(hdc, X, Y, hIcon); + if(!ret) OutTraceE("DrawIcon ERROR: err=%d\n", GetLastError()); + return ret; +} + + +BOOL WINAPI extDrawIconEx( HDC hdc, int xLeft, int yTop, HICON hIcon, int cxWidth, int cyWidth, UINT istepIfAniCur, HBRUSH hbrFlickerFreeDraw, UINT diFlags) +{ + BOOL ret; + OutTraceDW("DrawIconEx: hdc=%x pos=(%d,%d) hicon=%x size=(%d,%d) istep=%x flags=%x\n", + hdc, xLeft, yTop, hIcon, cxWidth, cyWidth, istepIfAniCur, diFlags); + if(dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_STRETCHED: + dxw.MapClient(&xLeft, &yTop, &cxWidth, &cyWidth); + OutTraceDW("DrawIconEx: fixed STRETCHED pos=(%d,%d) size=(%d,%d)\n", xLeft, yTop, cxWidth, cyWidth); + break; + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pDrawIconEx)(sdc.GetHdc(), xLeft, yTop, hIcon, cxWidth, cyWidth, istepIfAniCur, hbrFlickerFreeDraw, diFlags); + sdc.PutPrimaryDC(hdc, TRUE, xLeft, yTop, cxWidth, cyWidth); + return ret; + break; + default: + break; + } + } + ret = (*pDrawIconEx)(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth, istepIfAniCur, hbrFlickerFreeDraw, diFlags); + if(!ret) OutTraceE("DrawIconEx ERROR: err=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extDrawCaption(HWND hwnd, HDC hdc, LPCRECT lprc, UINT uFlags) +{ + BOOL ret; + OutTraceDW("DrawCaption: hwnd=%x hdc=%x rect=(%d,%d)-(%d,%d) flags=%x\n", hwnd, hdc, lprc->left, lprc->top, lprc->right, lprc->bottom, uFlags); + if(dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_STRETCHED: + dxw.MapClient((LPRECT)lprc); + OutTraceDW("DrawIconEx: fixed STRETCHED rect=(%d,%d)-(%d,%d)\n", lprc->left, lprc->top, lprc->right, lprc->bottom); + break; + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pDrawCaption)(hwnd, sdc.GetHdc(), lprc, uFlags); + sdc.PutPrimaryDC(hdc, TRUE, lprc->left, lprc->top, lprc->right, lprc->bottom); + return ret; + break; + default: + break; + } + } + ret = (*pDrawCaption)(hwnd, hdc, lprc, uFlags); + if(!ret) OutTraceE("DrawCaption ERROR: err=%d\n", GetLastError()); + return ret; +} + +BOOL WINAPI extPaintDesktop(HDC hdc) +{ + BOOL ret; + OutTraceDW("PaintDesktop: hdc=%x\n", hdc); + if(dxw.IsToRemap(hdc)){ + switch(dxw.GDIEmulationMode){ + case GDIMODE_SHAREDDC: + sdc.GetPrimaryDC(hdc); + ret=(*pPaintDesktop)(sdc.GetHdc()); + sdc.PutPrimaryDC(hdc, TRUE); + return ret; + break; + default: + break; + } + } + ret = (*pPaintDesktop)(hdc); + if(!ret) OutTraceE("PaintDesktop ERROR: err=%d\n", GetLastError()); + return ret; +} \ No newline at end of file diff --git a/dll/virtualdc.cpp b/dll/virtualdc.cpp new file mode 100644 index 0000000..008b0d7 --- /dev/null +++ b/dll/virtualdc.cpp @@ -0,0 +1,219 @@ +#define _CRT_SECURE_NO_WARNINGS +#define SYSLIBNAMES_DEFINES + +#include +#include "dxwnd.h" +#include "dxwcore.hpp" +#include "syslibs.h" +#include "dxhelper.h" +#include "resource.h" +#include "hddraw.h" +extern GetDC_Type pGetDC; +extern ReleaseDC_Type pReleaseDC; +extern HandleDDThreadLock_Type pReleaseDDThreadLock; + +#define OutTraceTMP OutTrace + +HDC dxwVDC::GetPrimaryDC() +{ + HDC PrimaryDC; + LPDIRECTDRAWSURFACE lpDDSPrim; + PrimaryDC = NULL; + lpDDSPrim = dxwss.GetPrimarySurface(); + if (lpDDSPrim) { + if(pReleaseDDThreadLock)(*pReleaseDDThreadLock)(); + (*pGetDC)(lpDDSPrim, &PrimaryDC); + while((PrimaryDC == NULL) && lpDDSPrim) { + OutTraceDW("GetFlippedDC: found primary surface with no DC, unref lpdds=%x\n", lpDDSPrim); + dxwss.UnrefSurface(lpDDSPrim); + lpDDSPrim = dxwss.GetPrimarySurface(); + if (lpDDSPrim) (*pGetDC)(lpDDSPrim, &PrimaryDC); + } + } + OutTrace("GetFlippedDC: return primary surface dc=%x\n", PrimaryDC); + return PrimaryDC; +} + +HDC dxwVDC::AcquireEmulatedDC(HWND hwnd, HDC *PrimaryDC) +{ + HDC wdc; + RECT WinRect; + HDC RealHDC; + +/*--------------------------------- + extern HDC hFlippedDC; + LPDIRECTDRAWSURFACE lpDDSPrim; + hFlippedDC = GetPrimaryDC(); + +----------------------------------*/ + if(!(wdc=(*pGDIGetDC)(hwnd))){ + OutTraceE("GetDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + return NULL; + } + RealHDC=wdc; + + RECT LastVRect; + LastVRect = VirtualPicRect; + + if(!(hwnd=WindowFromDC(wdc))) + OutTraceE("WindowFromDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + (*pGetClientRect)(hwnd, &WinRect); + if(dxw.IsDesktop(hwnd)){ + // when screen resolution changes, better renew service resources + VirtualPicRect = dxw.GetScreenRect(); + if((LastVRect.right != VirtualPicRect.right) || (LastVRect.bottom != VirtualPicRect.bottom)) { + DeleteObject(VirtualHDC); + VirtualHDC = NULL; + DeleteObject(VirtualPic); + VirtualPic = NULL; + } + } + else { + VirtualPicRect = WinRect; + dxw.UnmapClient(&VirtualPicRect); + } + + + OutTraceB("AcquireEmulatedDC: hwnd=%x Desktop=%x WinRect=(%d,%d)(%d,%d) VirtRect=(%d,%d)(%d,%d)\n", + hwnd, dxw.IsDesktop(hwnd), + WinRect.left, WinRect.top, WinRect.right, WinRect.bottom, + VirtualPicRect.left, VirtualPicRect.top, VirtualPicRect.right, VirtualPicRect.bottom); + + + if (!VirtualHDC){ + OutTraceB("AcquireEmulatedDC: INITIALIZE\n"); + if(!(VirtualHDC=CreateCompatibleDC(wdc))) + OutTraceE("CreateCompatibleDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + + if(!(VirtualPic=CreateCompatibleBitmap(wdc, dxw.GetScreenWidth(), dxw.GetScreenHeight()))) + OutTraceE("CreateCompatibleBitmap: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + + if(!SelectObject(VirtualHDC, VirtualPic)) + OutTraceE("SelectObject: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + +/*---------------------------------*/ + //HRGN hRgn; + //RECT screen; + //screen = dxw.GetScreenRect(); + //hRgn = CreateRectRgnIndirect(&screen); + //SelectClipRgn (VirtualHDC, hRgn); + //screen = dxw.GetScreenRect(); + //hRgn = CreateRectRgnIndirect(&screen); + //SelectClipRgn (wdc, hRgn); +/*---------------------------------*/ +/*---------------------------------*/ + if (!(hwnd == dxw.GethWnd())) { + POINT father, child, offset; + father.x = father.y = 0; + child.x = child.y = 0; + (*pClientToScreen)(dxw.GethWnd(),&father); + (*pClientToScreen)(hwnd,&child); + offset.x = child.x - father.x; + offset.y = child.y - father.y; + dxw.UnmapClient(&offset); + OutTraceDW("AcquireEmulatedDC: child window hwnd=%x offset=(%d,%d)\n", hwnd, offset.x, offset.y); + (*pSetViewportOrgEx)(VirtualHDC, offset.x, offset.y, NULL); + } + else + (*pSetViewportOrgEx)(VirtualHDC, 0, 0, NULL); + + + if(*PrimaryDC = GetPrimaryDC()){ // better copy from virtual primary .... + OutTraceTMP("AcquireEmulatedDC: intialize from primary dc=%x\n", PrimaryDC); + if(!(*pGDIBitBlt)(VirtualHDC, 0, 0, VirtualPicRect.right, VirtualPicRect.bottom, *PrimaryDC, 0, 0, SRCCOPY)) + OutTraceE("StretchBlt: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + } + else { // otherwise stretch from current windows DC + OutTraceTMP("AcquireEmulatedDC: intialize from windows dc=%x\n", wdc); + if(!(*pGDIStretchBlt)(VirtualHDC, 0, 0, VirtualPicRect.right, VirtualPicRect.bottom, wdc, 0, 0, WinRect.right, WinRect.bottom, SRCCOPY)) + OutTraceE("StretchBlt: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + } + } + + return VirtualHDC; +} + +BOOL dxwVDC::ReleaseEmulatedDC(HWND hwnd) +{ + HDC wdc; + RECT WinRect; + HDC PrimaryDC; + + (*pGetClientRect)(hwnd, &WinRect); + + OutTraceB("ReleaseEmulatedDC: hwnd=%x Desktop=%x WinRect=(%d,%d)(%d,%d) VirtRect=(%d,%d)(%d,%d)\n", + hwnd, dxw.IsDesktop(hwnd), + WinRect.left, WinRect.top, WinRect.right, WinRect.bottom, + VirtualPicRect.left, VirtualPicRect.top, VirtualPicRect.right, VirtualPicRect.bottom); + + if(PrimaryDC = GetPrimaryDC()){ // better copy from virtual primary .... + OutTraceTMP("AcquireEmulatedDC: flush to from primary dc=%x\n", PrimaryDC); + if(!(*pGDIBitBlt)(PrimaryDC, VirtualPicRect.left, VirtualPicRect.top, VirtualPicRect.right, VirtualPicRect.bottom, VirtualHDC, 0, 0, SRCCOPY)) + OutTraceE("StretchBlt: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + } + else + { + if(!(wdc=(*pGDIGetDC)(hwnd))) + OutTraceE("GetDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + OutTraceTMP("AcquireEmulatedDC: flush to windows dc=%x\n", wdc); + SetStretchBltMode(wdc, HALFTONE); + if(!(*pGDIStretchBlt)(wdc, 0, 0, WinRect.right, WinRect.bottom, VirtualHDC, 0, 0, VirtualPicRect.right, VirtualPicRect.bottom, SRCCOPY)) + OutTraceE("StretchBlt: ERROR err=%d at=%d\n", GetLastError(), __LINE__); + } + (*pGDIReleaseDC)(hwnd, VirtualHDC); + + return TRUE; +} + +void dxwVDC::ResetEmulatedDC() +{ + VirtualHDC=NULL; + VirtualPic=NULL; + VirtualOffsetX=0; + VirtualOffsetY=0; +} + +BOOL dxwVDC::IsVirtual(HDC hdc) +{ + return (hdc==VirtualHDC) /* && (dwFlags3 & GDIEMULATEDC)*/; +} + +#if 0 +BOOL dxwCore::ReleaseSharedDC(HWND hwnd, HDC hDC) +{ + HRESULT ret; + LPDIRECTDRAWSURFACE lpDDSPrim; + lpDDSPrim = dxwss.GetPrimarySurface(); + if(!lpDDSPrim) return(TRUE); + OutTraceDW("GDI.ReleaseDC: releasing flipped GDI hdc=%x\n", hDC); + ret=(*pReleaseDC)(dxwss.GetPrimarySurface(), hDC); + if (!(hwnd == dxw.GethWnd())) { + POINT father, child, offset; + RECT rect; + HDC hdc; + father.x = father.y = 0; + child.x = child.y = 0; + (*pClientToScreen)(dxw.GethWnd(),&father); + (*pClientToScreen)(hwnd,&child); + offset.x = child.x - father.x; + offset.y = child.y - father.y; + if(offset.x || offset.y){ + // if the graphis was blitted to primary but below a modal child window, + // bring that up to the window surface to make it visible. + BOOL ret2; + (*pGetClientRect)(hwnd, &rect); + hdc=(*pGDIGetDC)(hwnd); + if(!hdc) OutTrace("GDI.ReleaseDC: GetDC ERROR=%d at %d\n", GetLastError(), __LINE__); + ret2=(*pGDIBitBlt)(hdc, rect.left, rect.top, rect.right, rect.bottom, hDC, offset.x, offset.y, SRCCOPY); + if(!ret2) OutTrace("GDI.ReleaseDC: BitBlt ERROR=%d at %d\n", GetLastError(), __LINE__); + ret2=(*pGDIReleaseDC)(hwnd, hdc); + if(!ret2)OutTrace("GDI.ReleaseDC: ReleaseDC ERROR=%d at %d\n", GetLastError(), __LINE__); + // this may flicker .... + (*pInvalidateRect)(hwnd, NULL, FALSE); + } + } + if (ret) OutTraceE("GDI.ReleaseDC ERROR: err=%x(%s) at %d\n", ret, ExplainDDError(ret), __LINE__); + else dxw.ScreenRefresh(); + return (ret == DD_OK); +} +#endif \ No newline at end of file diff --git a/host/TabCompat.cpp b/host/TabCompat.cpp index 5261a4d..58a2352 100644 --- a/host/TabCompat.cpp +++ b/host/TabCompat.cpp @@ -42,6 +42,7 @@ void CTabCompat::DoDataExchange(CDataExchange* pDX) DDX_Check(pDX, IDC_EASPORTSHACK, cTarget->m_EASportsHack); DDX_Check(pDX, IDC_LEGACYALLOC, cTarget->m_LegacyAlloc); DDX_Check(pDX, IDC_DISABLEMAXWINMODE, cTarget->m_DisableMaxWinMode); + DDX_Check(pDX, IDC_DISABLEDISABLEALTTAB, cTarget->m_DisableDisableAltTab); DDX_Check(pDX, IDC_NOIMAGEHLP, cTarget->m_NoImagehlp); DDX_Check(pDX, IDC_REPLACEPRIVOPS, cTarget->m_ReplacePrivOps); diff --git a/host/TabSysLibs.cpp b/host/TabSysLibs.cpp index 1f3d310..2b074d2 100644 --- a/host/TabSysLibs.cpp +++ b/host/TabSysLibs.cpp @@ -31,7 +31,6 @@ void CTabSysLibs::DoDataExchange(CDataExchange* pDX) DDX_Check(pDX, IDC_CLIENTREMAPPING, cTarget->m_ClientRemapping); DDX_Radio(pDX, IDC_GDINONE, cTarget->m_DCEmulationMode); DDX_Check(pDX, IDC_FIXTEXTOUT, cTarget->m_FixTextOut); - DDX_Check(pDX, IDC_SHAREDDC, cTarget->m_SharedDC); DDX_Check(pDX, IDC_NOFILLRECT, cTarget->m_NoFillRect); DDX_Check(pDX, IDC_REUSEEMULATEDDC, cTarget->m_ReuseEmulatedDC); DDX_Check(pDX, IDC_CREATEDESKTOP, cTarget->m_CreateDesktop); diff --git a/host/TargetDlg.cpp b/host/TargetDlg.cpp index 91239ca..9e3b627 100644 --- a/host/TargetDlg.cpp +++ b/host/TargetDlg.cpp @@ -2,6 +2,7 @@ // #include "stdafx.h" +#include "shlwapi.h" #include "dxwndhost.h" #include "TargetDlg.h" @@ -59,6 +60,7 @@ CTargetDlg::CTargetDlg(CWnd* pParent /*=NULL*/) m_EASportsHack = FALSE; m_LegacyAlloc = FALSE; m_DisableMaxWinMode = FALSE; + m_DisableDisableAltTab = FALSE; m_NoImagehlp = FALSE; m_ReplacePrivOps = FALSE; m_ForcesHEL = FALSE; @@ -103,8 +105,8 @@ CTargetDlg::CTargetDlg(CWnd* pParent /*=NULL*/) m_Windowize = TRUE; // default true !! m_HotPatch = FALSE; m_HookDLLs = TRUE; // default true !! - m_TerminateOnClose = FALSE; // default true !! - m_ConfirmOnClose = FALSE; // default true !! + m_TerminateOnClose = FALSE; + m_ConfirmOnClose = FALSE; m_HookEnabled = TRUE; // default true !! m_EmulateRegistry = FALSE; m_OverrideRegistry = FALSE; @@ -231,19 +233,6 @@ BOOL CTargetDlg::OnInitDialog() int i=0; AfxEnableControlContainer(); CDialog::OnInitDialog(); -#if 0 - m_tabdxTabCtrl.InsertItem(i++, _T("Main")); - m_tabdxTabCtrl.InsertItem(i++, _T("Video")); - m_tabdxTabCtrl.InsertItem(i++, _T("Input")); - m_tabdxTabCtrl.InsertItem(i++, _T("DirectX")); - m_tabdxTabCtrl.InsertItem(i++, _T("Timing")); - m_tabdxTabCtrl.InsertItem(i++, _T("Log")); - m_tabdxTabCtrl.InsertItem(i++, _T("Libs")); - m_tabdxTabCtrl.InsertItem(i++, _T("Compat")); - m_tabdxTabCtrl.InsertItem(i++, _T("Registry")); - m_tabdxTabCtrl.InsertItem(i++, _T("Notes")); - if (gbDebug) m_tabdxTabCtrl.InsertItem(i++, _T("Debug")); -#else char sCaption[48+1]; LoadString(AfxGetResourceHandle(), DXW_TAB_MAIN, sCaption, sizeof(sCaption)); m_tabdxTabCtrl.InsertItem(i++, _T(sCaption)); @@ -269,7 +258,6 @@ BOOL CTargetDlg::OnInitDialog() m_tabdxTabCtrl.InsertItem(i++, _T(sCaption)); LoadString(AfxGetResourceHandle(), DXW_TAB_DEBUG, sCaption, sizeof(sCaption)); if (gbDebug) m_tabdxTabCtrl.InsertItem(i++, _T(sCaption)); -#endif m_tabdxTabCtrl.Init(); return TRUE; } @@ -293,7 +281,94 @@ BEGIN_MESSAGE_MAP(CTargetDlg, CDialog) //{{AFX_MSG_MAP(CTargetDlg) //}}AFX_MSG_MAP + ON_BN_CLICKED(IDTRY, &CTargetDlg::OnBnClickedTry) + ON_BN_CLICKED(IDKILL, &CTargetDlg::OnBnClickedKill) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CTargetDlg Message Handler + +void CTargetDlg::OnBnClickedTry() +{ +#if 0 + NMHDR nmh; + nmh.code = ID_PRUN; + nmh.idFrom = NULL; + nmh.hwndFrom = NULL; + this->GetParent()->SendMessage(WM_NOTIFY, 0, (LPARAM)&nmh); +#else + char path[MAX_PATH+1]; + char fullpath[MAX_PATH+1]; + char sMsg[81]; + int iHookStatus; + STARTUPINFO sinfo; + PROCESS_INFORMATION pinfo; + TARGETMAP RestrictedMaps[2]; + extern void SetTargetFromDlg(TARGETMAP *, CTargetDlg *); + extern BOOL CheckStatus(void); + + static BOOL IsLocked = FALSE; + if(IsLocked) return; + if (CheckStatus()) return; // don't try when status is active + IsLocked = TRUE; + m_tabdxTabCtrl.OnOK(); + SetTargetFromDlg(&RestrictedMaps[0], this); + memset(&RestrictedMaps[1], 0, sizeof(TARGETMAP)); + strcpy_s(path, sizeof(path), m_FilePath.GetBuffer()); + PathRemoveFileSpec(path); + SetTarget(RestrictedMaps); + iHookStatus=GetHookStatus(NULL); + if(iHookStatus == DXW_IDLE) StartHook(); + if(m_StartDebug){ + extern DWORD WINAPI StartDebug(void *); + TARGETMAP TargetMap; + PRIVATEMAP PrivateMap; + ThreadInfo_Type ThreadInfo; + strcpy(TargetMap.path, m_FilePath); + strcpy(PrivateMap.launchpath, m_LaunchPath); + ThreadInfo.TM=&TargetMap; + ThreadInfo.PM=&PrivateMap; + CloseHandle(CreateThread( NULL, 0, StartDebug, &ThreadInfo, 0, NULL)); + } + else{ + ZeroMemory(&sinfo, sizeof(sinfo)); + sinfo.cb = sizeof(sinfo); + strncpy(fullpath, m_LaunchPath.IsEmpty() ? m_FilePath.GetBuffer() : m_LaunchPath.GetBuffer(), MAX_PATH); + if(!CreateProcess(NULL, fullpath, + 0, 0, false, CREATE_DEFAULT_ERROR_MODE, NULL, path, &sinfo, &pinfo)){ + sprintf(sMsg, "CreateProcess ERROR %d", GetLastError()); + MessageBox(sMsg, "Error", MB_ICONEXCLAMATION); + } + CloseHandle(pinfo.hProcess); // no longer needed, avoid handle leakage + CloseHandle(pinfo.hThread); // no longer needed, avoid handle leakage + } + // wait & recover + Sleep(5000); + //SetTarget(CDxwndhostView::TargetMaps); + if(iHookStatus == DXW_IDLE) EndHook(); + IsLocked = FALSE; +#endif +} + +void CTargetDlg::OnBnClickedKill() +{ + char FilePath[MAX_PATH+1]; + char *lpProcName, *lpNext; + HRESULT res; + extern BOOL KillProcByName(char *, BOOL); + + strncpy(FilePath, m_FilePath.GetBuffer(), MAX_PATH); + lpProcName=FilePath; + while (lpNext=strchr(lpProcName,'\\')) lpProcName=lpNext+1; + + if(!KillProcByName(lpProcName, FALSE)){ + wchar_t *wcstring = new wchar_t[48+1]; + mbstowcs_s(NULL, wcstring, 48, lpProcName, _TRUNCATE); + res=MessageBoxLangArg(DXW_STRING_KILLTASK, DXW_STRING_WARNING, MB_YESNO | MB_ICONQUESTION, wcstring); + if(res!=IDYES) return; + KillProcByName(lpProcName, TRUE); + } + else{ + MessageBoxLang(DXW_STRING_NOKILLTASK, DXW_STRING_INFO, MB_ICONEXCLAMATION); + } +} \ No newline at end of file diff --git a/host/TargetDlg.h b/host/TargetDlg.h index a48428c..441aea8 100644 --- a/host/TargetDlg.h +++ b/host/TargetDlg.h @@ -199,6 +199,7 @@ public: BOOL m_EASportsHack; BOOL m_LegacyAlloc; BOOL m_DisableMaxWinMode; + BOOL m_DisableDisableAltTab; BOOL m_NoImagehlp; BOOL m_ForcesHEL; BOOL m_SetZBufferBitDepths; @@ -256,6 +257,8 @@ protected: public: virtual BOOL OnInitDialog(); + afx_msg void OnBnClickedTry(); + afx_msg void OnBnClickedKill(); }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ Will insert additional declarations immediately before the previous line. diff --git a/host/dxwndhost.aps b/host/dxwndhost.aps index 2cda1edae6bd71f5d908367e366b9a72d3058cd3..9285cee761c454b517c86f0423ed7aaab33a0f81 100644 GIT binary patch delta 29783 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 btXKm+l=u{h9hAtP0X~$Nb{6=I^Hu#ncx^r3 delta 10679 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 PVsSXy{SxCht*!ijC1!(I diff --git a/host/dxwndhost.cpp b/host/dxwndhost.cpp index 30d2006..f70ece3 100644 --- a/host/dxwndhost.cpp +++ b/host/dxwndhost.cpp @@ -34,6 +34,8 @@ END_MESSAGE_MAP() UINT m_StartToTray = FALSE; UINT m_InitialState = DXW_ACTIVE; BOOL gbDebug = FALSE; +BOOL gTransientMode = FALSE; +int iProgIndex; extern char m_ConfigFileName[20+1] = "dxwnd.ini"; class CNewCommandLineInfo : public CCommandLineInfo @@ -50,6 +52,13 @@ char LangString[20+1] = {0}; void CNewCommandLineInfo::ParseParam(LPCTSTR lpszParam, BOOL bFlag, BOOL bLast) { + // syntax: + // /t -- start minimized in tray icon + // /i -- start in idle state + // /d -- start in debug mode + // /lang= -- loads the language resources in Resources_.dll extension + // /c: -- loads config file instead of default dxwnd.ini + // /e -- terminates (Ends) the active dxwnd session if(bFlag) { CString sParam(lpszParam); if (sParam.MakeLower() == "t"){ @@ -87,6 +96,13 @@ void CNewCommandLineInfo::ParseParam(LPCTSTR lpszParam, BOOL bFlag, BOOL bLast) KillProcByName("DxWnd.exe", TRUE); exit(0); } + if (sParam.Left(2).MakeLower() == "r:"){ + gTransientMode = TRUE; + m_StartToTray=TRUE; + char *p = (char *)sParam.GetString(); + iProgIndex = atoi(&p[2]); + return; + } } // Call the base class to ensure proper command line processing diff --git a/host/dxwndhost.h b/host/dxwndhost.h index 29d0071..f6cb68f 100644 --- a/host/dxwndhost.h +++ b/host/dxwndhost.h @@ -34,6 +34,12 @@ typedef struct PRIVATEMAP char *registry; }PRIVATEMAP; +typedef struct { + TARGETMAP *TM; + PRIVATEMAP *PM; +} ThreadInfo_Type; +ThreadInfo_Type; + extern char gInitPath[MAX_PATH]; ///////////////////////////////////////////////////////////////////////////// diff --git a/host/dxwndhost.rc b/host/dxwndhost.rc index e063715b23d1fcd19193f419e2b69414dda89100..e9173e9a3a13d2b951982b3dda772db314e9a816 100644 GIT binary patch delta 894 zcmYjPT}YE*6h6mq8>L^Ct|lhg7}dp^ZQr;5nN8a=N)bv4yhyav48?w&kTJwd>1Qbi zdv8R`tDul<)NVwKB&e&3F1iRYsGAV8R5UNF^KJ@qF5aK>JkL4rbKaRZrp5QB=Wm@k zL2!T-H1L8u`O*0+3-#n{y}(FwUVBL;bVDb!Ll0EKO>jdOv@y07uJK8(SK$`4@U4}1 zopjmbRW#5@^Oha0fhNY>W@I;XY~x4;nPEI!;rl2=XyU1vYJ7I)>XJ(XWGI!qW>$`E zR?1Y2rK`m@*|P60#$D%-`52#@pmVTdp9nZHpRC?Jtm$S=vj~MSml~&4F&@Dk$#s7K zX{6Rhy(e<%NazCf>Bo&a=-{LF;9a^Gv>mKt!5$VomJS=6bcUO)gY!_&`vBu22dcP{ z4vwvC6=SM79BigU6jEixBG#g)CPzYvm*ko>kSk)y^Mi{q8hAJ))=Svnq`stq?zE`X zyJ*|x-G${f0uk=rCfd;%|NPtT?AjqqOXXmH; zKOT_2^hoh@a}%p&6#uT0b$Lt)f=ix7xyq(lR^sTRa}*ZSaWv4Em3hU(x-u^>lG&>X zRNR}4#(Xw&ZfzLZ=d@;Way_ajt_*?7H^xvS+z89JiT!cRCfC0)PVyv9@mkIKI(eqN7xkzME>J|z6E^Y8fcD*b+Mcahxar1MO-z|l6*eRG z)90mfT3F2$Yer1a%(5jlY{Gd(wB}%&Xxxd#=oP49h3L=5;a4g?$!BwY^zD;5HC2oa Yhq&5AC0^v0dH6kfr_q_>|7U6V59!SI&Hw-a delta 520 zcmYjOO=uHg5d9{*DccwlYubnuf`*=onCwr|ETxS(S+G*9(nDzrDo77r^j7eY-a-Wh zpYnn95Q>P0QUZ%^j}d=BPYI~llaU^}2f>!MYGc|un|hG%FyGAMy?HaU`Jv;@>yFC1 z)Ulj6D^3fYpY7CBKLVsXuZ)vH=Zif_C>d7J5QfNLZ}1)xg*2`YPM}neJ6DIEyg>D% z8a0`(3rnOqW`%{WxfB|oRE*AsQ9KAE@-=NNa~RzX^_c${8HQ}(JGO+0G4BCdyX9cJJ1)0|FuW0l_j3uwo2ncM zQ8&uJRv9)#t_|1LHI#pQkE^8OPIDNXJGH$9A{%3^JZeuhXX(!(DLIjL3j6a4WpTTi z$ID8$j1%2g21K^4!{bShXqlziJqr7I`8hz3n0M62$5#|uLBmxk?Os#qeSp`0XH`m-Nx&*GRt*P)5xxF#DKEhr`z{Glq%h+OUD_LdmnLd=~C(RW22kJ6&= zNY*2imm?9HMQzG(m!tIjgyJ9K%vub0Hxq6tN$2}Wm-S0D-FB?Ytt*srCofQZ<}ZGi Butfj> diff --git a/host/dxwndhost.vs2008.suo b/host/dxwndhost.vs2008.suo index 7d227fc1b10dc52b0a53cefcc02f61db7c276dbb..125f4fd3c2ee637faf65e1292c658680332f4cdc 100644 GIT binary patch literal 80384 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, sizeof(t->path), dlg->m_FilePath); strcpy_s(t->module, sizeof(t->module), dlg->m_Module); @@ -221,6 +223,7 @@ static void SetTargetFromDlg(TARGETMAP *t, CTargetDlg *dlg) case 0: break; case 1: t->flags2 |= GDISTRETCHED; break; case 2: t->flags3 |= GDIEMULATEDC; break; + case 3: t->flags6 |= SHAREDDC; break; //case 3: t->flags |= MAPGDITOPRIMARY; break; } @@ -300,6 +303,7 @@ static void SetTargetFromDlg(TARGETMAP *t, CTargetDlg *dlg) if(dlg->m_EASportsHack) t->flags5 |= EASPORTSHACK; if(dlg->m_LegacyAlloc) t->flags6 |= LEGACYALLOC; if(dlg->m_DisableMaxWinMode) t->flags6 |= DISABLEMAXWINMODE; + if(dlg->m_DisableDisableAltTab) t->flags7 |= DISABLEDISABLEALTTAB; if(dlg->m_NoImagehlp) t->flags5 |= NOIMAGEHLP; if(dlg->m_ForcesHEL) t->flags3 |= FORCESHEL; if(dlg->m_SetZBufferBitDepths) t->flags6 |= SETZBUFFERBITDEPTHS; @@ -335,7 +339,6 @@ static void SetTargetFromDlg(TARGETMAP *t, CTargetDlg *dlg) if(dlg->m_CursorClipping) t->flags |= CLIPCURSOR; if(dlg->m_VideoToSystemMem) t->flags |= SWITCHVIDEOMEMORY; if(dlg->m_FixTextOut) t->flags |= FIXTEXTOUT; - if(dlg->m_SharedDC) t->flags6 |= SHAREDDC; if(dlg->m_HookGlide) t->flags4 |= HOOKGLIDE; if(dlg->m_RemapMCI) t->flags5 |= REMAPMCI; if(dlg->m_NoMovies) t->flags6 |= NOMOVIES; @@ -472,6 +475,7 @@ static void SetDlgFromTarget(TARGETMAP *t, CTargetDlg *dlg) dlg->m_DCEmulationMode = 0; if(t->flags2 & GDISTRETCHED) dlg->m_DCEmulationMode = 1; if(t->flags3 & GDIEMULATEDC) dlg->m_DCEmulationMode = 2; + if(t->flags6 & SHAREDDC ) dlg->m_DCEmulationMode = 3; //if(t->flags & MAPGDITOPRIMARY) dlg->m_DCEmulationMode = 3; dlg->m_ResTypes = 0; @@ -525,6 +529,7 @@ static void SetDlgFromTarget(TARGETMAP *t, CTargetDlg *dlg) dlg->m_EASportsHack = t->flags5 & EASPORTSHACK ? 1 : 0; dlg->m_LegacyAlloc = t->flags6 & LEGACYALLOC ? 1 : 0; dlg->m_DisableMaxWinMode = t->flags6 & DISABLEMAXWINMODE ? 1 : 0; + dlg->m_DisableDisableAltTab = t->flags7 & DISABLEDISABLEALTTAB ? 1 : 0; dlg->m_NoImagehlp = t->flags5 & NOIMAGEHLP ? 1 : 0; dlg->m_ForcesHEL = t->flags3 & FORCESHEL ? 1 : 0; dlg->m_SetZBufferBitDepths = t->flags6 & SETZBUFFERBITDEPTHS ? 1 : 0; @@ -1075,6 +1080,10 @@ void CDxwndhostView::OnInitialUpdate() this->isUpdated=FALSE; pTitles = &PrivateMaps[0]; pTargets= &TargetMaps[0]; + + if(gTransientMode){ + this->OnRun(); + } } ///////////////////////////////////////////////////////////////////////////// @@ -1753,9 +1762,10 @@ DWORD WINAPI TrayIconUpdate(CSystemTray *Tray) char sMsg[1024]; char *Status; char DllVersion[21]; - int TickCount; + int TickCount, IdleCount; PrevDxStatus=-1; // a different one... TickCount=0; + IdleCount=0; while (TRUE) { // once a second ... Sleep(1000); @@ -1770,10 +1780,18 @@ DWORD WINAPI TrayIconUpdate(CSystemTray *Tray) TickCount=0; Tray->StopAnimation(); Tray->SetIcon(IconId); + if(gTransientMode) { + IdleCount++; + if(IdleCount > 2) { + delete(Tray->GetAncestor(GA_ROOTOWNER)); + exit(0); + } + } } else { // animation state machine .... TickCount++; + IdleCount=0; if (DxStatus!=PrevDxStatus) { Tray->SetIcon(IconId); } @@ -1999,12 +2017,6 @@ static char *ExceptionCaption(DWORD ec) // For thread messaging #define DEBUG_EVENT_MESSAGE WM_APP + 0x100 -typedef struct { - TARGETMAP *TM; - PRIVATEMAP *PM; -} ThreadInfo_Type; -ThreadInfo_Type ThreadInfo; - DWORD WINAPI StartDebug(void *p) { ThreadInfo_Type *ThInfo; @@ -2137,22 +2149,37 @@ DWORD WINAPI StartDebug(void *p) void CDxwndhostView::OnRun() { + static BOOL IsLocked = FALSE; + if(IsLocked) return; + IsLocked = TRUE; CListCtrl& listctrl = GetListCtrl(); POSITION pos; int i; STARTUPINFO sinfo; PROCESS_INFORMATION pinfo; char path[MAX_PATH]; + TARGETMAP RestrictedMaps[2]; //extern CString GetFileNameFromHandle(HANDLE); - if(!listctrl.GetSelectedCount()) return; - pos = listctrl.GetFirstSelectedItemPosition(); - i = listctrl.GetNextSelectedItem(pos); + if(gTransientMode){ + i=iProgIndex-1; + if(i<0) i=0; + } + else { + if(!listctrl.GetSelectedCount()) return; + pos = listctrl.GetFirstSelectedItemPosition(); + i = listctrl.GetNextSelectedItem(pos); + } ZeroMemory(&sinfo, sizeof(sinfo)); sinfo.cb = sizeof(sinfo); + // create a virtually single entry in the targetmap array + memcpy(&RestrictedMaps[0], &TargetMaps[i], sizeof(TARGETMAP)); + memset(&RestrictedMaps[1], 0, sizeof(TARGETMAP)); strcpy_s(path, sizeof(path), TargetMaps[i].path); PathRemoveFileSpec(path); + SetTarget(RestrictedMaps); if(TargetMaps[i].flags2 & STARTDEBUG){ + ThreadInfo_Type ThreadInfo; ThreadInfo.TM=&TargetMaps[i]; ThreadInfo.PM=&PrivateMaps[i]; CloseHandle(CreateThread( NULL, 0, StartDebug, &ThreadInfo, 0, NULL)); @@ -2164,6 +2191,10 @@ void CDxwndhostView::OnRun() CloseHandle(pinfo.hProcess); // no longer needed, avoid handle leakage CloseHandle(pinfo.hThread); // no longer needed, avoid handle leakage } + // wait & recover + Sleep(5000); + SetTarget(TargetMaps); + IsLocked = FALSE; } void SwitchToColorDepth(int bpp) diff --git a/host/host.aps b/host/host.aps index 9c58adf48a5c2cf54aba73c72af2f577f651bba3..79481915e2332b5da052bf32209e54a8f13bd66c 100644 GIT binary patch delta 1049 zcmXxiUr19?90%~->%HlAZ@Qct+jZ_wn@-nsbDBtqe;~v%rf`O)?9k@UmlP@-k%V$0C2(cI1SSoT4#DK|NF?@lJei^aKPtadD9NzD_Gv5Q`B~rmvf0cE6Xdo@XE#W_TAWa^Sn16JolI%Mzwi_ zcTk?oRxQdZigQU`99J7yEU2{W^cvV9Q6pMh_(Z}d2I}}t!iU#B8nR9o6~Kv~U({eg z7&o%(PJJmTP!0d&`$236Ig5o*9{PX3A;ApBHo}5=IQtRC$1rCdb@0`3Hc=;-m$CN| z!CagjMQ{+|>{JSb#Hk6OJ1> z%fyk2(^p(oZE>N_Gj*5{D#%rRGi=RVJx=0Ak`G%=3Klk*q+s{0Uv6)O(P}JgDpEJp zO~3RKwVQr9(}q+VT|FIt#wZ=<@RZgaEYmuIU9+VNsV-xosL1s_u=N-S6cs6q+M-`x z>BX~N(sWRTQ9AhAk9Ym_Utk@}ML+fJ(mH|f^w2wqlL6veiu44vTOsK$uFyJz`&<5h DtYCo9 delta 663 zcmXBQKWGzC90&0C9zE$%DWQZC&XSkdK)h6AtEUukuuzHz>S~8Tgl0&f)Y?dC!NH+} z2Srl8tB6B~9+Wg`(?0Sw99#k_LOVDWzv){(2fy#{_wM~(?NqIvs#;3s z*3!cxM|B}e_X?9sPv=U7#aqSE+ePnAvAQr*C_k^h%zJmucVR||W_7tPbNF4)%JsG7 zo0cbq_zQnat4W2ta;&RDhy;QyEei-~0};a&3v-rp(ft{AL(3t!l#>muyj~=G9jnF3 zHwakfB>jMh;aML}`pmJMY-)KKF1-$)3RIf>a}4>IbE!LD8o-kQ(>;!e9k0-#?_h6h zIS+SRtJWai51Q`d1P&9XdjkPGej%g}5V0>lg!3!r%G0oSwA_SCU&G(g>L`hN(y`)Z zS(YCmq`Wf2<1`M_CcFl_)!oOX4frjserE7BW5RI+EYBjOpAa!T%i<(!!iTVTyVrN= zH~70+^^D+8&V_BXVIYv*zN9Hy6s{450B{zUbOXp9n94? diff --git a/host/resource b/host/resource index 2d616eae00f25c463bbddb08973cabe6144ae9cb..3f2648f31928c876db48f9b68dcf16b5a3342248 100644 GIT binary patch delta 152 zcmZoz#&mB5(}V|;jZ*a{KM)X@timV39>NgB5XoRP`5}+~WC2FD$(vZECLby{0J3>N z?2Qj*nNPlEp)h%th0SCmONGhbfV7gn!sZ~$O$w6>QfwwWL@7)*2CATv=2iF5CZv=_cMwznolmQl-(Sbvq}vBomep> delta 79 zcmV-V0I>hwr~-hd0+8U7@B#$0<^h&BlSEq{lbSg`lYBWKllVD2lh`>RlW;%;vsgN= lAd`+%2D4~eW(t!ATRZ_ZlW}?*lQ0ehv(9CR2eYzmtR^!kAK3r^