From 899c2bdd08f966f9fe1b40d24d1b85e2c941ee25 Mon Sep 17 00:00:00 2001 From: gho tik Date: Sat, 19 Sep 2015 12:41:27 -0400 Subject: [PATCH] v2_03_37_src Former-commit-id: 6f33c63743b2ec691fc3002c7ac628f8b7d52ce4 --- Include/dxwnd.h | 4 +- build/dxwnd.dll | 4 +- build/dxwnd.exe | 4 +- build/exports/dxwnd.ini | 5 + build/exports/dxwnd.reg | 5 + build/readme-relnotes.txt | 11 + build/registry/dxwnd.SimCity 2000.reg | 47 + dll/advapi.cpp | 425 +++- dll/ddblit.cpp | 31 +- dll/ddraw.cpp | 12 +- dll/dxhook.cpp | 6 +- dll/dxwnd.aps | Bin 37668 -> 37668 bytes dll/dxwnd.cpp | 2 +- dll/dxwnd.vs2008.sln | 20 - dll/dxwnd.vs2008.suo | Bin 493568 -> 540672 bytes dll/hd3d7.cpp | 83 +- dll/user32.cpp | 69 +- dll/user32.old.cpp | 3099 +++++++++++++++++++++++++ dll/winmm.cpp | 2 + host/TabDebug.cpp | 1 - host/TabDirectX.cpp | 2 +- host/TabSysLibs.cpp | 3 + host/TargetDlg.cpp | 5 +- host/TargetDlg.h | 3 +- host/dxTabCtrl.h | 2 +- host/dxwnd.ini | 38 + host/dxwndhost.aps | Bin 160172 -> 132756 bytes host/dxwndhost.h | 4 +- host/dxwndhost.rc | Bin 104488 -> 104888 bytes host/dxwndhost.vs2008.sln | 20 - host/dxwndhost.vs2008.suo | Bin 280064 -> 7168 bytes host/dxwndhostView.cpp | 147 +- host/resource | Bin 36778 -> 36960 bytes 33 files changed, 3732 insertions(+), 322 deletions(-) create mode 100644 build/exports/dxwnd.ini create mode 100644 build/exports/dxwnd.reg create mode 100644 build/registry/dxwnd.SimCity 2000.reg delete mode 100644 dll/dxwnd.vs2008.sln create mode 100644 dll/user32.old.cpp create mode 100644 host/dxwnd.ini delete mode 100644 host/dxwndhost.vs2008.sln diff --git a/Include/dxwnd.h b/Include/dxwnd.h index c1315ce..f1018cc 100644 --- a/Include/dxwnd.h +++ b/Include/dxwnd.h @@ -20,7 +20,7 @@ #define HANDLEEXCEPTIONS 0x00000040 // Handles exceptions: Div by 0 .... #define SAVELOAD 0x00000080 #define EMULATEBUFFER 0x00000100 -#define AUTOMATIC 0x00000200 +// #define AUTOMATIC 0x00000200 #define BLITFROMBACKBUFFER 0x00000400 #define SUPPRESSCLIPPING 0x00000800 #define AUTOREFRESH 0x00001000 @@ -201,6 +201,8 @@ #define SETZBUFFERBITDEPTHS 0x00020000 // when not set, set the legacy dwZBufferBitDepths field in the directdraw capability from GetCaps() #define SHAREDDC 0x00040000 // enable sharing window DC and primary surface DC #define WOW32REGISTRY 0x00080000 // Sets KEY_WOW32_64KEY registry flag +#define STRETCHMOVIES 0x00100000 // Stretches ActiveMovie Windows to the whole window size +#define BYPASSMCI 0x00200000 // bypass all MCI calls returning OK. // logging Tflags DWORD: #define OUTTRACE 0x00000001 // enables tracing to dxwnd.log in general diff --git a/build/dxwnd.dll b/build/dxwnd.dll index 5df4d43..9e98ca8 100644 --- a/build/dxwnd.dll +++ b/build/dxwnd.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f2fe03b12248b3b75bf4e724f83017b2767ac7eaf5f5c25ac2021da81ba9dd23 -size 585728 +oid sha256:e0833b7f9d40095e84bf9c7fa9697bed48c0967e153970a8ba9c9aa146ecc554 +size 587776 diff --git a/build/dxwnd.exe b/build/dxwnd.exe index 4b98fce..ff91f44 100644 --- a/build/dxwnd.exe +++ b/build/dxwnd.exe @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:482a21422742238d783015f22714a6001eac5a1dc38332c53db686dcd086c7c3 -size 544256 +oid sha256:99558d172cbd24a33a7c5be255b7dc89f52ff58addce4b330a463d47878a1b70 +size 544768 diff --git a/build/exports/dxwnd.ini b/build/exports/dxwnd.ini new file mode 100644 index 0000000..a6b5445 --- /dev/null +++ b/build/exports/dxwnd.ini @@ -0,0 +1,5 @@ +[window] +posx=1280 +posy=341 +sizx=320 +sizy=200 diff --git a/build/exports/dxwnd.reg b/build/exports/dxwnd.reg new file mode 100644 index 0000000..6439a60 --- /dev/null +++ b/build/exports/dxwnd.reg @@ -0,0 +1,5 @@ +[HKEY_LOCAL_MACHINE\SOFTWARE\MicroProse\Star Trek Generations] +[HKEY_LOCAL_MACHINE\SOFTWARE\MicroProse\Star Trek Generations\1.0] +"Path"="D:\\GAMES\\STGEN" +"CDPath"="F:\\GENS" +"InstallSet"="MED" diff --git a/build/readme-relnotes.txt b/build/readme-relnotes.txt index 48db031..6edb74b 100644 --- a/build/readme-relnotes.txt +++ b/build/readme-relnotes.txt @@ -900,3 +900,14 @@ fix: CreateCompatibleDC hooker printing wrong error messages in normal condition fix: fixed DrawText, DrawTextEx hookers returning wrong RECT structure. Fixes "Star Trek Armada" text placement problems add: completed log messages for DrawTextEx, CreateDialogParam, DialogBoxParam and CreateDialogIndirectParam +v2.03.37: +add: handling of RegEnumValue advapi call in virtual registry. Useful for "Star trek Generations" +add: virtual registry now integrated in dxwnd.ini configuration and activated automatically. No more handling of dxwnd.reg file +fix: virtual registry optimization, code reorganization, bug fixing .... +add: "Stretch ActiveMovie window" flag. Fixes "The Thing" intro movies. +fix: apply "Blit from backbuffer" option to both surface emulated and non emulated cases. Should help fixing "Galapagos" screen locks. +fix: apply "Limit screen resolution" to the list of detected video modes in VGA emulated case +fix: eliminated "Automatic" surface emulation mode, no longer supported +fix: fixed InvalidateRect rectangle: avoids flickering in "Microsoft Pandora's Box" +add: added "Bypass MCI calls" flag. + diff --git a/build/registry/dxwnd.SimCity 2000.reg b/build/registry/dxwnd.SimCity 2000.reg new file mode 100644 index 0000000..9728bbc --- /dev/null +++ b/build/registry/dxwnd.SimCity 2000.reg @@ -0,0 +1,47 @@ +[HKEY_CURRENT_USER\SOFTWARE] +[HKEY_CURRENT_USER\SOFTWARE\Maxis] +[HKEY_CURRENT_USER\SOFTWARE\Maxis\SimCity 2000] +[HKEY_CURRENT_USER\SOFTWARE\Maxis\SimCity 2000\Localize] +"Language"="USA" + +[HKEY_CURRENT_USER\SOFTWARE\Maxis\SimCity 2000\Options] +"AutoBudget"=dword:00000000 +"AutoGoto"=dword:00000001 +"AutoSave"=dword:00000000 +"Disasters"=dword:00000001 +"Music"=dword:00000001 +"Sound"=dword:00000001 +"Speed"=dword:00000001 + +[HKEY_CURRENT_USER\SOFTWARE\Maxis\SimCity 2000\Paths] +"Cities"="D:\\Games\\Simcity 2000\\Cities" +"Data"="D:\\Games\\Simcity 2000\\Data" +"Goodies"="D:\\Games\\Simcity 2000\\Goodies" +"Graphics"="D:\\Games\\Simcity 2000\\Bitmaps" +"Home"="D:\\Games\\Simcity 2000" +"Music"="D:\\Games\\Simcity 2000\\Sounds" +"SaveGame"="D:\\Games\\Simcity 2000\\Cities" +"Folder"="Maxis" +"Scenarios"="D:\\Games\\Simcity 2000\\Scenario" +"TileSets"="D:\\Games\\Simcity 2000\\ScurkArt" + +[HKEY_CURRENT_USER\SOFTWARE\Maxis\SimCity 2000\Registration] +"Company Name"="nameless mutual loan company" +"Mayor Name"="Jane Doe" + +[HKEY_CURRENT_USER\SOFTWARE\Maxis\SimCity 2000\SCURK] +"CycleColors"=dword:00000001 +"GridHeight"=dword:00000008 +"GridWidth"=dword:00000008 +"ShowClipRegion"=dword:00000000 +"ShowDrawGrid"=dword:00000000 +"SnapToGrid"=dword:00000000 +"Sound"=dword:00000001 + +[HKEY_CURRENT_USER\SOFTWARE\Maxis\SimCity 2000\Version] +"SimCity 2000"=dword:00000100 +"SCURK"=dword:00000100 + +[HKEY_CURRENT_USER\SOFTWARE\Maxis\SimCity 2000\Windows] +"Color Check"=dword:00000000 +"Display"="8 1" diff --git a/dll/advapi.cpp b/dll/advapi.cpp index 84eab58..93f484f 100644 --- a/dll/advapi.cpp +++ b/dll/advapi.cpp @@ -65,7 +65,13 @@ static char *hKey2String(HKEY hKey) //OutTrace("building fake Key=\"%s\" hKey=%x\n", sKey, hKey); fclose(regf); strcpy(sKey, &RegBuf[1]); - sKey[strlen(sKey)-2]=0; // get rid of "]" + //sKey[strlen(sKey)-2]=0; // get rid of "]" + for(int i=strlen(sKey)-1; i; i--){ + if(sKey[i]==']'){ + sKey[i]=0; + break; + } + } return sKey; } else { @@ -89,20 +95,258 @@ static char *hKey2String(HKEY hKey) return skey; } +static char *Unescape(char *s, char **dest) +{ + if(!*dest) *dest=(char *)malloc(strlen(s)+100); + else *dest=(char *)realloc(*dest, strlen(s)+100); + char *t = *dest; + for(; *s; s++){ + if((*s=='\\') && (*(s+1)=='n')){ + *t++ = '\n'; + s++; + } + else{ + *t++ = *s; + } + } + *t=0; + return *dest; +} + static FILE *OpenFakeRegistry() { DWORD dwAttrib; char sSourcePath[MAX_PATH+1]; char *p; + static BOOL LoadFromConfig = TRUE; dwAttrib = GetFileAttributes("dxwnd.dll"); if (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) return NULL; GetModuleFileName(GetModuleHandle("dxwnd"), sSourcePath, MAX_PATH); p=&sSourcePath[strlen(sSourcePath)-strlen("dxwnd.dll")]; + if(LoadFromConfig){ + int Index; + char key[81]; + char name[MAX_PATH+1]; + char exepath[MAX_PATH+1]; + strcpy(p, "dxwnd.ini"); + GetModuleFileName(0, name, MAX_PATH); + //for(int i = 0; name[i]; i ++) name[i] = tolower(name[i]); + for(Index=0; Index0){ + char *FileBuf = NULL; + Unescape(RegBuf, &FileBuf); + strcpy(p, "dxwnd.reg"); + freg = fopen(sSourcePath,"w"); + fwrite(FileBuf, 1, strlen(FileBuf), freg); + fclose(freg); + free(FileBuf); + } + free(RegBuf); + } + LoadFromConfig = FALSE; + } strcpy(p, "dxwnd.reg"); return fopen(sSourcePath,"r"); } -// --------------------------------------------------------------------------------- +static LONG SeekFakeKey(FILE *regf, HKEY hKey) +{ + LONG res; + res = ERROR_FILE_NOT_FOUND; + char RegBuf[MAX_PATH+1]; + HKEY hCurKey=HKEY_FAKE+1; + fgets(RegBuf, 256, regf); + while (!feof(regf)){ + if(RegBuf[0]=='['){ + hCurKey--; + } + if(hCurKey==hKey) { + //OutTraceB("DEBUG: SeekFakeKey fount key at line=%s\n", RegBuf); + res = ERROR_SUCCESS; + break; + } + fgets(RegBuf, 256, regf); + } + return res; +} + +static LONG SeekValueName(FILE *regf, LPCTSTR lpValueName) +{ + LONG res; + char RegBuf[MAX_PATH+1]; + long KeySeekPtr; + res = ERROR_FILE_NOT_FOUND; + KeySeekPtr = ftell(regf); + fgets(RegBuf, 256, regf); + while (!feof(regf)){ + if((RegBuf[0]=='"') && + !_strnicmp(lpValueName, &RegBuf[1], strlen(lpValueName)) && + (RegBuf[strlen(lpValueName)+1]=='"') && + (RegBuf[strlen(lpValueName)+2]=='=')) + { + fseek(regf, KeySeekPtr, SEEK_SET); + return ERROR_SUCCESS; + } + if(RegBuf[0]=='[') return res; + KeySeekPtr = ftell(regf); + fgets(RegBuf, 256, regf); + } + return res; +} + +static LONG SeekValueIndex(FILE *regf, DWORD dwIndex, LPCTSTR lpValueName, LPDWORD lpcchValueName) +{ + LONG res; + char RegBuf[MAX_PATH+1]; + long KeySeekPtr; + res = ERROR_NO_MORE_ITEMS; + KeySeekPtr = ftell(regf); + fgets(RegBuf, 256, regf); + dwIndex++; + while (!feof(regf) && dwIndex){ + if(RegBuf[0]=='"') dwIndex--; + if(dwIndex == 0){ + fseek(regf, KeySeekPtr, SEEK_SET); + //sscanf(RegBuf, "\"%s\"=", lpValueName); + strncpy((char *)lpValueName, strtok(&RegBuf[1], "\""), *lpcchValueName); + *lpcchValueName = strlen(lpValueName); + //OutTrace("DEBUG: lpValueName=%s len=%d\n", lpValueName, *lpcchValueName); + return ERROR_SUCCESS; + } + if(RegBuf[0]=='[') return res; + KeySeekPtr = ftell(regf); + fgets(RegBuf, 256, regf); + } + return res; +} + +static DWORD GetKeyValue( + FILE *regf, + char *ApiName, + LPCTSTR lpValueName, + LPDWORD lpType, // beware: could be NULL + LPBYTE lpData, // beware: could be NULL + LPDWORD lpcbData) +{ + LONG res; + LPBYTE lpb; + char *pData; + char RegBuf[MAX_PATH+1]; + DWORD cbData=0; + + OutTrace("GetKeyValue: ValueName=%s", lpValueName); + fgets(RegBuf, 256, regf); + pData=&RegBuf[strlen(lpValueName)+3]; + lpb = lpData; + if(lpcbData) { + cbData = *lpcbData; + *lpcbData=0; + } + do { + if(*pData=='"'){ // string value + if(lpType) *lpType=REG_SZ; + pData++; + while(*pData && (*pData != '"')){ + if(*pData=='\\') pData++; + if(lpData && lpcbData) if(*lpcbData < cbData) *lpb++=*pData; + pData++; + if(lpcbData) (*lpcbData)++; + } + if(lpcbData) (*lpcbData)++; // extra space for string terminator ? + if(lpData && lpcbData) if(*lpcbData < cbData) *lpb = 0; // string terminator + OutTraceR("%s: type=REG_SZ cbData=%x Data=\"%s\"\n", + ApiName, lpcbData ? *lpcbData : 0, lpData ? (char *)lpData : "(NULL)"); + res=(*lpcbData > cbData) ? ERROR_MORE_DATA : ERROR_SUCCESS; + break; + } + if(!strncmp(pData,"dword:",strlen("dword:"))){ //dword value + DWORD val; + if(lpType) *lpType=REG_DWORD; + pData+=strlen("dword:"); + sscanf(pData, "%x", &val); + if(lpData) { + if (cbData >= sizeof(DWORD)) { + memcpy(lpData, &val, sizeof(DWORD)); + res=ERROR_SUCCESS; + } + else + res=ERROR_MORE_DATA; + } + if (lpcbData) *lpcbData=sizeof(DWORD); + OutTraceR("%s: type=REG_DWORD cbData=%x Data=0x%x\n", + ApiName, lpcbData ? *lpcbData : 0, val); + break; + } + if(!strncmp(pData,"hex:",strlen("hex:"))){ //hex value + BYTE *p; + if(lpType) *lpType=REG_BINARY; + p = (BYTE *)pData; + p+=strlen("hex:"); + while(TRUE){ + p[strlen((char *)p)-1]=0; // eliminates \n at the end of line + while(strlen((char *)p)>1){ + if((*lpcbData < cbData) && lpData){ + sscanf((char *)p, "%x,", (char *)lpb); + lpb++; + } + p+=3; + if(lpcbData) (*lpcbData)++; + } + if(p[strlen((char *)p)-1]=='\\'){ + fgets(RegBuf, 256, regf); + pData = RegBuf; + p = (BYTE *)pData; + } + else break; + } + OutTraceR("%s: type=REG_BINARY cbData=%d Data=%s\n", + ApiName, + lpcbData ? *lpcbData : 0, + lpData ? "(NULL)" : hexdump(lpData, *lpcbData)); + res=(*lpcbData > cbData) ? ERROR_MORE_DATA : ERROR_SUCCESS; + break; + } + } while(FALSE); + return res; +} + +static void LogKeyValue(char *ApiName, LONG res, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) +{ + char sInfo[1024]; + if(res) { + OutTrace("%s: ERROR res=%x\n", ApiName, res); + return; + } + sprintf(sInfo, "%s: res=0 size=%d type=%x(%s)", + ApiName, lpcbData?*lpcbData:0, lpType?*lpType:0, lpType?ExplainRegType(*lpType):"none"); + if(lpType && lpData && lpcbData) { + DWORD cbData = *lpcbData; + switch(*lpType){ + case REG_SZ: sprintf(sInfo, "%s Data=\"%*.*s\"\n", sInfo, cbData-1, cbData-1, lpData); break; + case REG_DWORD: sprintf(sInfo, "%s Data=0x%x\n", sInfo, *(DWORD *)lpData); break; + case REG_BINARY: sprintf(sInfo, "%s Data=%s\n", sInfo, hexdump((BYTE *)lpData, cbData)); break; + case REG_NONE: sprintf(sInfo, "%s Data=\"%s\"\n", sInfo, lpData); break; + default: sprintf(sInfo, "%s Data=???\n", sInfo); break; + } + } + else + sprintf(sInfo, "%s\n", sInfo); + OutTrace(sInfo); +} static LONG myRegOpenKeyEx( HKEY hKey, @@ -139,6 +383,7 @@ static LONG myRegOpenKeyEx( return ERROR_FILE_NOT_FOUND; } +// --------------------------------------------------------------------------------- LONG WINAPI extRegOpenKeyEx( HKEY hKey, @@ -183,138 +428,26 @@ LONG WINAPI extRegQueryValueEx( LPDWORD lpcbData) { LONG res; + FILE *regf; + DWORD cbData=0; OutTraceR("RegQueryValueEx: hKey=%x(\"%s\") ValueName=\"%s\" Reserved=%x lpType=%x lpData=%x lpcbData=%x\n", hKey, hKey2String(hKey), lpValueName, lpReserved, lpType, lpData, lpcbData); if (!IsFake(hKey)){ res=(*pRegQueryValueEx)(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); - if(IsTraceR){ - if (res==ERROR_SUCCESS){ - OutTrace("RegQueryValueEx: size=%d type=%x(%s) ", - lpcbData?*lpcbData:0, lpType?*lpType:0, lpType?ExplainRegType(*lpType):"none"); - if(lpType && lpData) switch(*lpType){ - case REG_SZ: OutTrace("Data=\"%s\"\n", lpData); break; - case REG_DWORD: OutTrace("Data=0x%x\n", *(DWORD *)lpData); break; - case REG_BINARY: - { - DWORD i; - unsigned char *p; - p = lpData; - OutTrace("Data=%02.2X", p++); - for(i=1; i<*lpcbData; i++) OutTrace(",%02.2X", *p++); - OutTrace("\n"); - } - break; - default: OutTrace("Data=???\n"); break; - } - else - OutTrace("\n"); - } - else - OutTrace("res=%x\n", res); - } + if(IsTraceR) LogKeyValue("RegQueryValueEx", res, lpType, lpData, lpcbData); return res; } - // try emulated registry - res = ERROR_FILE_NOT_FOUND; - FILE *regf; - char RegBuf[MAX_PATH+1]; - char *pData; - HKEY hCurKey=HKEY_FAKE+1; - DWORD cbData=0; regf=OpenFakeRegistry(); - if(regf==NULL) return res; - if(!lpValueName)lpValueName=""; - fgets(RegBuf, 256, regf); - while (!feof(regf)){ - if(RegBuf[0]=='['){ - hCurKey--; - } - else { - if(hCurKey==hKey){ - if((RegBuf[0]=='"') && - !_strnicmp(lpValueName, &RegBuf[1], strlen(lpValueName)) && - (RegBuf[strlen(lpValueName)+1]=='"') && - (RegBuf[strlen(lpValueName)+2]=='=')) - { - LPBYTE lpb; - res=ERROR_FILE_NOT_FOUND; - pData=&RegBuf[strlen(lpValueName)+3]; - lpb = lpData; - if(lpcbData) { - cbData = *lpcbData; - *lpcbData=0; - } - if(*pData=='"'){ // string value - if(lpType) *lpType=REG_SZ; - pData++; - while(*pData && (*pData != '"')){ - if(*pData=='\\') pData++; - if(lpData && lpcbData) if(*lpcbData < cbData) *lpb++=*pData; - pData++; - if(lpcbData) (*lpcbData)++; - } - if(lpcbData) (*lpcbData)++; // extra space for string terminator ? - if(lpData && lpcbData) if(*lpcbData < cbData) *lpb = 0; // string terminator - OutTraceR("RegQueryValueEx: type=REG_SZ cbData=%x Data=\"%s\"\n", - lpcbData ? *lpcbData : 0, lpData ? (char *)lpData : "(NULL)"); - res=(*lpcbData > cbData) ? ERROR_MORE_DATA : ERROR_SUCCESS; - break; - } - if(!strncmp(pData,"dword:",strlen("dword:"))){ //dword value - DWORD val; - if(lpType) *lpType=REG_DWORD; - pData+=strlen("dword:"); - sscanf(pData, "%x", &val); - if(lpData) { - if (cbData >= sizeof(DWORD)) { - memcpy(lpData, &val, sizeof(DWORD)); - res=ERROR_SUCCESS; - } - else - res=ERROR_MORE_DATA; - } - if (lpcbData) *lpcbData=sizeof(DWORD); - OutTraceR("RegQueryValueEx: type=REG_DWORD cbData=%x Data=0x%x\n", - lpcbData ? *lpcbData : 0, val); - break; - } - if(!strncmp(pData,"hex:",strlen("hex:"))){ //hex value - BYTE *p; - if(lpType) *lpType=REG_BINARY; - p = (BYTE *)pData; - p+=strlen("hex:"); - while(TRUE){ - p[strlen((char *)p)-1]=0; // eliminates \n at the end of line - while(strlen((char *)p)>1){ - if((*lpcbData < cbData) && lpData){ - sscanf((char *)p, "%x,", (char *)lpb); - lpb++; - } - p+=3; - if(lpcbData) (*lpcbData)++; - } - if(p[strlen((char *)p)-1]=='\\'){ - fgets(RegBuf, 256, regf); - pData = RegBuf; - p = (BYTE *)pData; - } - else break; - } - OutTraceR("RegQueryValueEx: type=REG_BINARY cbData=%d Data=%s\n", - lpcbData ? *lpcbData : 0, - lpData ? "(NULL)" : hexdump(lpData, *lpcbData)); - res=(*lpcbData > cbData) ? ERROR_MORE_DATA : ERROR_SUCCESS; - break; - } - } - } - } - fgets(RegBuf, 256, regf); - } + if(regf==NULL) return ERROR_FILE_NOT_FOUND; + res = SeekFakeKey(regf, hKey); + if(res != ERROR_SUCCESS) return res; + res = SeekValueName(regf, lpValueName); + if(res != ERROR_SUCCESS) return res; + res = GetKeyValue(regf, "RegQueryValueEx", lpValueName, lpType, lpData, lpcbData); + if(IsTraceR) LogKeyValue("RegQueryValueEx", res, lpType, lpData, lpcbData); fclose(regf); - OutTraceR("RegQueryValueEx: res=%x\n", res); return res; } @@ -383,9 +516,43 @@ LONG WINAPI extRegCreateKey(HKEY hKey, LPCTSTR lpSubKey, PHKEY phkResult) LONG WINAPI extRegEnumValueA(HKEY hKey, DWORD dwIndex, LPTSTR lpValueName, LPDWORD lpcchValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) { - LONG ret; - OutTrace("RegEnumValue: hKey=%x(%s) Index=%x\n", hKey, hKey2String(hKey), dwIndex); - ret=(*pRegEnumValueA)(hKey, dwIndex, lpValueName, lpcchValueName, lpReserved, lpType, lpData, lpcbData); - OutTrace("RegEnumValue: hKey=%x(%s) Index=%x ValueName=\"%s\", Type=%x ret=%x\n", hKey, hKey2String(hKey), dwIndex, lpValueName, lpType ? *lpType : 0, ret); - return ret; + LONG res; + + OutTraceR("RegEnumValue: hKey=%x(\"%s\") index=%d cchValueName=%d Reserved=%x lpType=%x lpData=%x lpcbData=%x\n", + hKey, hKey2String(hKey), dwIndex, *lpcchValueName, lpReserved, lpType, lpData, lpcbData); + if (!IsFake(hKey)){ + res=(*pRegEnumValueA)(hKey, dwIndex, lpValueName, lpcchValueName, lpReserved, lpType, lpData, lpcbData); + if(IsTraceR) LogKeyValue("RegQueryValueEx", res, lpType, lpData, lpcbData); + return res; + } + + // try emulated registry + FILE *regf; + regf=OpenFakeRegistry(); + if(regf==NULL) return ERROR_FILE_NOT_FOUND; + res = SeekFakeKey(regf, hKey); + if(res != ERROR_SUCCESS) return res; + res = SeekValueIndex(regf, dwIndex, lpValueName, lpcchValueName); + if(res != ERROR_SUCCESS) return res; + res = GetKeyValue(regf, "RegEnumValue", lpValueName, lpType, lpData, lpcbData); + if(IsTraceR) LogKeyValue("RegEnumValue", res, lpType, lpData, lpcbData); + fclose(regf); + return res; } + +#ifdef TOBEDONE +LONG WINAPI RegQueryInfoKey( + _In_ HKEY hKey, + _Out_opt_ LPTSTR lpClass, + _Inout_opt_ LPDWORD lpcClass, + _Reserved_ LPDWORD lpReserved, + _Out_opt_ LPDWORD lpcSubKeys, + _Out_opt_ LPDWORD lpcMaxSubKeyLen, + _Out_opt_ LPDWORD lpcMaxClassLen, + _Out_opt_ LPDWORD lpcValues, + _Out_opt_ LPDWORD lpcMaxValueNameLen, + _Out_opt_ LPDWORD lpcMaxValueLen, + _Out_opt_ LPDWORD lpcbSecurityDescriptor, + _Out_opt_ PFILETIME lpftLastWriteTime +); +#endif \ No newline at end of file diff --git a/dll/ddblit.cpp b/dll/ddblit.cpp index 693df6c..cea0f48 100644 --- a/dll/ddblit.cpp +++ b/dll/ddblit.cpp @@ -20,6 +20,7 @@ extern CreateSurface2_Type pCreateSurface4; extern CreateSurface2_Type pCreateSurface7; extern Unlock4_Type pUnlockMethod(LPDIRECTDRAWSURFACE); extern HDC hFlippedDC; +extern BOOL bFlippedDC; extern ReleaseDC_Type pReleaseDC; extern void BlitError(HRESULT, LPRECT, LPRECT, int); @@ -36,7 +37,8 @@ static HRESULT sBltNoPrimary(char *api, LPDIRECTDRAWSURFACE lpdds, LPRECT lpdest //extern PrimaryBlt_Type pPrimaryBlt; //CkArg arg; - FromScreen=dxwss.IsAPrimarySurface(lpddssrc) && !(dxw.dwFlags1 & EMULATESURFACE) && !(dxw.dwFlags1 & EMULATEBUFFER); // v2.02.77 + //FromScreen=dxwss.IsAPrimarySurface(lpddssrc) && !(dxw.dwFlags1 & EMULATESURFACE) && !(dxw.dwFlags1 & EMULATEBUFFER); // v2.02.77 + FromScreen=dxwss.IsAPrimarySurface(lpddssrc); // ghogho // make a working copy of srcrect if not NULL if (lpsrcrect){ @@ -48,15 +50,24 @@ static HRESULT sBltNoPrimary(char *api, LPDIRECTDRAWSURFACE lpdds, LPRECT lpdest // v2.1.83: BLITFROMBACKBUFFER mode, let you chose to blit from backbuffer, where the surface size // is fixed no matter how the window/primary surface is scaled. // In "The Sims" there is no quality loss, but some scrolling artifact. - if(lpsrcrect && FromScreen){ - LPDIRECTDRAWSURFACE lpDDSBack; - lpDDSBack = dxwss.GetBackBufferSurface(); - if(lpDDSBack && (dxw.dwFlags1 & BLITFROMBACKBUFFER)){ - lpddssrc=lpDDSBack; - srcrect=dxw.GetScreenRect(); + //if(lpsrcrect && FromScreen){ + if(FromScreen){ + if ((dxw.dwFlags1 & EMULATESURFACE) || (dxw.dwFlags1 & EMULATEBUFFER)){ + if(dxw.dwFlags1 & BLITFROMBACKBUFFER){ + LPDIRECTDRAWSURFACE lpDDSBack; + lpDDSBack = dxwss.GetBackBufferSurface(); + if(lpDDSBack) lpddssrc=lpDDSBack; + } } - else{ - srcrect=dxw.MapWindowRect(lpsrcrect); + else { + if(dxw.dwFlags1 & BLITFROMBACKBUFFER){ + LPDIRECTDRAWSURFACE lpDDSBack; + lpDDSBack = dxwss.GetBackBufferSurface(); + if(lpDDSBack) lpddssrc=lpDDSBack; + } + else{ + srcrect=dxw.MapWindowRect(lpsrcrect); + } } } @@ -274,7 +285,7 @@ static HRESULT sBltToPrimary(char *api, LPDIRECTDRAWSURFACE lpdds, LPRECT lpdest // Try to handle HDC lock concurrency.... if(res==DDERR_SURFACEBUSY){ - (*pReleaseDC)(lpdds, hFlippedDC); + if (bFlippedDC) (*pReleaseDC)(lpdds, hFlippedDC); #if 0 res=(*pUnlockMethod(lpddssrc))(lpddssrc, NULL); if(res && (res!=DDERR_NOTLOCKED)) OutTraceE("Unlock ERROR: lpdds=%x err=%x(%s)\n", lpddssrc, res, ExplainDDError(res)); diff --git a/dll/ddraw.cpp b/dll/ddraw.cpp index 65265e1..6d4040a 100644 --- a/dll/ddraw.cpp +++ b/dll/ddraw.cpp @@ -1868,7 +1868,11 @@ HRESULT WINAPI extQueryInterfaceS(void *lpdds, REFIID riid, LPVOID *obp) } // fix the target for gamma ramp creation: if it is a primary surface, use the real one!! - if(dxwss.IsAPrimarySurface((LPDIRECTDRAWSURFACE)lpdds) && IsGammaRamp) lpdds = lpDDSEmu_Prim; + // v2.03.37: do this just when in esurface emulated mode!! + if( IsGammaRamp && + (dxw.dwFlags1 & EMULATESURFACE) && + dxwss.IsAPrimarySurface((LPDIRECTDRAWSURFACE)lpdds)) + lpdds = lpDDSEmu_Prim; res = (*pQueryInterfaceS)(lpdds, riid, obp); @@ -2444,6 +2448,7 @@ static HRESULT BuildPrimaryDir(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurf if(IsDebug) DescribeSurface(*lplpdds, dxversion, "DDSPrim(2)", __LINE__); } + iBakBufferVersion=dxversion; // v2.03.37 HookDDSurfacePrim(lplpdds, dxversion); if(dxw.dwFlags1 & CLIPCURSOR) dxw.SetClipCursor(); @@ -4176,7 +4181,7 @@ HRESULT WINAPI EnumModesCallbackDumper(LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID l OutTrace("EnumModesCallback:\n"); OutTrace("\tdwSize=%d\n", lpDDSurfaceDesc->dwSize); OutTrace("\tdwFlags=%x(%s)\n", lpDDSurfaceDesc->dwFlags, ExplainFlags(lpDDSurfaceDesc->dwFlags)); - OutTrace("\tdwHeight x dwWidth=(%d,%d)\n", lpDDSurfaceDesc->dwHeight, lpDDSurfaceDesc->dwWidth); + OutTrace("\tdwWidth x dwHeight=(%d,%d)\n", lpDDSurfaceDesc->dwWidth, lpDDSurfaceDesc->dwHeight); OutTrace("\tlPitch=%d\n", lpDDSurfaceDesc->lPitch); OutTrace("\tdwBackBufferCount=%d\n", lpDDSurfaceDesc->dwBackBufferCount); OutTrace("\tdwRefreshRate=%d\n", lpDDSurfaceDesc->dwRefreshRate); @@ -4347,6 +4352,8 @@ HRESULT WINAPI extEnumDisplayModes(EnumDisplayModes1_Type pEnumDisplayModes, LPD for (ResIdx=0; SupportedRes[ResIdx].h; ResIdx++){ EmuDesc.dwHeight=SupportedRes[ResIdx].h; EmuDesc.dwWidth=SupportedRes[ResIdx].w; + if((dxw.dwFlags4 & LIMITSCREENRES) && + CheckResolutionLimit((LPDDSURFACEDESC)&EmuDesc)) break; EmuDesc.ddpfPixelFormat.dwSize=sizeof(DDPIXELFORMAT); EmuDesc.ddpfPixelFormat.dwFlags=DDPF_RGB; for (DepthIdx=0; SupportedDepths[DepthIdx]; DepthIdx++) { @@ -4593,6 +4600,7 @@ HRESULT WINAPI extAddAttachedSurface(LPDIRECTDRAWSURFACE lpdds, LPDIRECTDRAWSURF if (res) { HRESULT sdres; DDSURFACEDESC2 sd; + if (res) OutTraceE("AddAttachedSurface: ERROR %x(%s) at %d\n", res, ExplainDDError(res), __LINE__); sd.dwSize=Set_dwSize_From_Surface(lpddsadd); sdres=lpddsadd->GetSurfaceDesc((DDSURFACEDESC *)&sd); if (sdres) diff --git a/dll/dxhook.cpp b/dll/dxhook.cpp index c8b98eb..f07af6f 100644 --- a/dll/dxhook.cpp +++ b/dll/dxhook.cpp @@ -52,7 +52,7 @@ CRITICAL_SECTION TraceCS; static char *FlagNames[32]={ "UNNOTIFY", "EMULATESURFACE", "CLIPCURSOR", "RESETPRIMARY", "HOOKDI", "MODIFYMOUSE", "HANDLEEXCEPTIONS", "SAVELOAD", - "EMULATEBUFFER", "AUTOMATIC", "BLITFROMBACKBUFFER", "SUPPRESSCLIPPING", + "EMULATEBUFFER", "--AUTOMATIC--", "BLITFROMBACKBUFFER", "SUPPRESSCLIPPING", "AUTOREFRESH", "FIXWINFRAME", "HIDEHWCURSOR", "SLOWDOWN", "ENABLECLIPPING", "LOCKWINSTYLE", "MAPGDITOPRIMARY", "FIXTEXTOUT", "KEEPCURSORWITHIN", "USERGB565", "SUPPRESSDXERRORS", "PREVENTMAXIMIZE", @@ -110,7 +110,7 @@ static char *Flag6Names[32]={ "FIXPITCH", "POWER2WIDTH", "HIDETASKBAR", "ACTIVATEAPP", "NOSYSMEMPRIMARY", "NOSYSMEMBACKBUF", "CONFIRMONCLOSE", "TERMINATEONCLOSE", "FLIPEMULATION", "SETZBUFFERBITDEPTHS", "SHAREDDC", "WOW32REGISTRY", - "", "", "", "", + "STRETCHMOVIES", "BYPASSMCI", "", "", "", "", "", "", "", "", "", "", }; @@ -1717,11 +1717,9 @@ void HookInit(TARGETMAP *target, HWND hwnd) sSourcePath[strlen(sSourcePath)-strlen("dxwnd.dll")] = 0; // terminate the string just before "dxwnd.dll" SetDllDirectory(sSourcePath); - if(dxw.dwFlags1 & AUTOMATIC) dxw.dwFlags1 |= EMULATESURFACE; // if AUTOMATIC, try this first! if(dxw.dwFlags5 & HYBRIDMODE) { // special mode settings .... dxw.dwFlags1 |= EMULATESURFACE; - // dxw.dwFlags5 |= NOSYSTEMEMULATED; dxw.dwFlags2 |= SETCOMPATIBILITY; dxw.dwFlags5 &= ~(BILINEARFILTER | AEROBOOST); } diff --git a/dll/dxwnd.aps b/dll/dxwnd.aps index 63d6be4b764dd3ca519cfcdbfca4d7ba68ad0827..caed8be93d5e61062efddb6d12e8ebd76eb2f8a8 100644 GIT binary patch delta 52 zcmZ3ojA_X-rU~Kf#^&)QMU_Sy@^MU{pd. #include "TlHelp32.h" -#define VERSION "2.03.36" +#define VERSION "2.03.37" #define DDTHREADLOCK 1 //#define LOCKTHREADS diff --git a/dll/dxwnd.vs2008.sln b/dll/dxwnd.vs2008.sln deleted file mode 100644 index 0d2e531..0000000 --- a/dll/dxwnd.vs2008.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dxwnd", "dxwnd.vs2008.vcproj", "{579E7FE7-2745-4100-A802-23511711FCDE}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {579E7FE7-2745-4100-A802-23511711FCDE}.Debug|Win32.ActiveCfg = Debug|Win32 - {579E7FE7-2745-4100-A802-23511711FCDE}.Debug|Win32.Build.0 = Debug|Win32 - {579E7FE7-2745-4100-A802-23511711FCDE}.Release|Win32.ActiveCfg = Release|Win32 - {579E7FE7-2745-4100-A802-23511711FCDE}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/dll/dxwnd.vs2008.suo b/dll/dxwnd.vs2008.suo index 06a5c31f80ec9b29920d7bf92cfe73d1aa880e35..26e6a8d07ac3d596ae90ff003c7055a508495a3c 100644 GIT binary patch delta 20493 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 delta 2908 zcmaJ@eNbH06@TZxd+%E|8(i1TO6iJkmj#(f;zH5{0qH^wC6K1b(AXxJtkisTrjtQS zGe|yM5fg$mLSE#w!NyD`vt+DeDVyQWWNh4|sD#mkIF6&yNw-W!oz|hzqNWakp0|lf z{_4)$eea%o?z!ij-|w9JVzEH1H>bC7fkV?YpppK$HI32B_xmdERYf5<0Q*@Nv?cbk zhk-q>S(AEqW^&ECb&LNs0XpeLN)zqe$sDhcf!VpaIjcvSp+Z`)CyVKM-}Uz*dY&iC zw%i_x3HcwMp)DXW&F0YErxzrq=ebHTy4x^uwv>Be9G?zA9`<%YHYNk$#T}cW)4J@) z#_TS*FkCa{U(IXw zJG(L0B&h)fBWd}L>q_tZX{qPmvr}`n{1=q1tu*W;-73F_1SKr7Yi$+mZ)#-$&Dz$q z3xd{HO;3qj(%ou3`N;Npi|DQ6npNxk+9K=nI`{td!?>l#D8F6P$}}gfRcgP~TD4zk z+pM|upV|?bSQd0-TV}MzIu^|`etyo@(ySM%?;n12`ZfqBzG_(w5(daS1N-{)d*utX z{@@O){fTxcw!V7eDd!Rr*f7(!*&mpRL%+#iE;49#S6V+Y{jw`;U96C}J86_ct@U)- z@^jdB*gQ9!$LeY%5tq} zb2ioogb&M`SOXp~A&9-T!0~ds;kM87svVCoH^8$AsGb9x?&qK{Rum6|w3@3ucyb+c zsT>m~0b{>|9FbrEL-&fMIeZ)Mv6u?yiY zo`>#DtN>k0n8Ruu$ii1%C;uyc2n_JxAkWA931w_P!_&F&s__UcGw_KSnXmGLZ~@TV z%$&-(5Wa@^DgvWwCHPencO2C*xg465e+yi?8z;wj4!RdnY{fNjR=@6e4@}PQe+;fz zygGLS`x-mO>D{4_I_*~}(& z?0in&fe}BKxbHFWDgThZ3F2E=(_qJ6bcSrV5mAvhS@Lo0Na(vTRVxeobEyeL&gyG1 z^b9xA9H#SQCIzzloZfDQJ`Sp?g}Q?)M}>Z+&S=qE2$>Cdz7QV3@QlpF%V&fGaxJLN z#fZ+6xVl7lpu^8kjP&SZ1_aX8pr$R|q&BddLXk;Q_+J%n-c)4dzw8FkeMMzM)f)6MCu$TJiQGejomNqYNr%F@F`}oM)kD zfLhwSOZZ}pN#R!RQhtnf)p6RD!&87AK{7f~#>4RlXS4uL9J96L}cv0w22nXgDzWitbXGNBEb3nRn5ly*ovg3Xk$G+I+Wt)KZ=j$UYWc zeESW))Vh3#C_csy(sH@IT+UO(pCBy8$c*s8HtaLuel$0M17kB}y7mLU72;Jqg72Qy zJvja$F*jAly*P1BcPRfw{vzOHF*S=`Q)H@eC%>d~yCJBoF84}Zf8)zFxz2W+d8#n!fud|2~=XhbeW5W{uUnQA{2Blz|n z!$25!Mwifd`(#Q)4_&9sX8yv-mDii_Mh;)T*oEIPMF8&x*d} z!}^^f8>^l262`^_rFL9U5*N;s@8jVNk%cq$%rm&KRzm;h_UZ*eZSt{&(O@{)L;%Nv6#YcI$Q-P3QB>P*@g!gV6r}cBy8YU2N~iCU_4CBzB;0;e*t$ga z5Oy0WU*F*=vHlrinvJ&FddS!hcw#eiqx-0l)n6A< zKAtY2Y9xM0j2tzpG1>@OYU-%b4OVQ5taQs<@^KHj^ZT1STc49XE!eOKf^Z++eukIX zm6?g=N+M8NDG#gE}5^IALUmam2Wh zaS!g>E4}DyGdy^xPY)sMG%6I`C}e7~kUk@ZR#NAU?ExqA0iIgHDsf^3EB^m~R()gO Ee}8Vv3;+NC diff --git a/dll/hd3d7.cpp b/dll/hd3d7.cpp index a403671..d5cea72 100644 --- a/dll/hd3d7.cpp +++ b/dll/hd3d7.cpp @@ -896,32 +896,12 @@ HRESULT WINAPI extCreateDevice2(void *lpd3d, REFCLSID Guid, LPDIRECTDRAWSURFACE OutTraceD3D("CreateDevice(D3D2): d3d=%x GUID=%x(%s) lpdds=%x%s\n", lpd3d, Guid.Data1, ExplainGUID((GUID *)&Guid), lpdds, dxwss.ExplainSurfaceRole((LPDIRECTDRAWSURFACE)lpdds)); - do { // fake loop - // first attempt - res=(*pCreateDevice2)(lpd3d, Guid, lpdds, lplpd3dd); - if(res==DD_OK) break; // no error, break - OutTraceE("CreateDevice(D3D2) ERROR: err=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); - if(!(dxw.dwFlags1 & EMULATESURFACE)) break; // no more tricks .... - if(!(dxw.dwFlags1 & AUTOMATIC)) break; - //OutTraceD3D("CreateDevice(D3D2): SYSMEMORY OFF\n"); - //dxw.dwFlags6 |= NOSYSMEMPRIMARY; - //res=(*pCreateDevice2)(lpd3d, Guid, lpdds, lplpd3dd); - //if(res==DD_OK) break; - //OutTraceE("CreateDevice(D3D2) ERROR: err=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); - //if(!(dxw.dwFlags1 & AUTOMATIC)) break; - - OutTraceD3D("CreateDevice(D3D2): Emulation OFF\n"); - //dxw.dwFlags5 &= ~NOSYSTEMEMULATED; - dxw.dwFlags1 &= ~EMULATESURFACE; - dxw.dwFlags1 |= LOCKEDSURFACE; - res=(*pCreateDevice2)(lpd3d, Guid, lpdds, lplpd3dd); - if(res==DD_OK) break; + res=(*pCreateDevice2)(lpd3d, Guid, lpdds, lplpd3dd); + if(res!=DD_OK) { OutTraceE("CreateDevice(D3D2) ERROR: err=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); - return res; - } while (FALSE); - - if(res == DD_OK){ + } + else{ OutTraceD3D("CreateDevice(D3D2): lpd3dd=%x\n", lpd3d, *lplpd3dd); HookDirect3DDevice((void **)lplpd3dd, 2); } @@ -935,32 +915,12 @@ HRESULT WINAPI extCreateDevice3(void *lpd3d, REFCLSID Guid, LPDIRECTDRAWSURFACE4 OutTraceD3D("CreateDevice(D3D3): d3d=%x GUID=%x(%s) lpdds=%x%s\n", lpd3d, Guid.Data1, ExplainGUID((GUID *)&Guid), lpdds, dxwss.ExplainSurfaceRole((LPDIRECTDRAWSURFACE)lpdds)); - do { // fake loop - // first attempt - res=(*pCreateDevice3)(lpd3d, Guid, lpdds, lplpd3dd, unk); - if(res==DD_OK) break; // no error, break - OutTraceE("CreateDevice(D3D3) ERROR: err=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); - if(!(dxw.dwFlags1 & EMULATESURFACE)) break; // no more tricks .... - if(!(dxw.dwFlags1 & AUTOMATIC)) break; - //OutTraceD3D("CreateDevice(D3D3): SYSMEMORY OFF\n"); - //dxw.dwFlags5 |= NOSYSTEMEMULATED; - //res=(*pCreateDevice3)(lpd3d, Guid, lpdds, lplpd3dd, unk); - //if(res==DD_OK) break; - //OutTraceE("CreateDevice(D3D3) ERROR: err=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); - //if(!(dxw.dwFlags1 & AUTOMATIC)) break; - - OutTraceD3D("CreateDevice(D3D3): Emulation OFF\n"); - //dxw.dwFlags5 &= ~NOSYSTEMEMULATED; - dxw.dwFlags1 &= ~EMULATESURFACE; - dxw.dwFlags1 |= LOCKEDSURFACE; - res=(*pCreateDevice3)(lpd3d, Guid, lpdds, lplpd3dd, unk); - if(res==DD_OK) break; + res=(*pCreateDevice3)(lpd3d, Guid, lpdds, lplpd3dd, unk); + if(res!=DD_OK) { OutTraceE("CreateDevice(D3D3) ERROR: err=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); - return res; - } while (FALSE); - - if(res == DD_OK){ + } + else{ OutTraceD3D("CreateDevice(D3D3): lpd3dd=%x\n", lpd3d, *lplpd3dd); HookDirect3DDevice((void **)lplpd3dd, 3); } @@ -978,35 +938,14 @@ HRESULT WINAPI extCreateDevice7(void *lpd3d, REFCLSID Guid, LPDIRECTDRAWSURFACE7 OutTraceD3D("CreateDevice(D3D7): d3d=%x GUID=%x(%s) lpdds=%x%s\n", lpd3d, Guid.Data1, ExplainGUID((GUID *)&Guid), lpdds, dxwss.ExplainSurfaceRole((LPDIRECTDRAWSURFACE)lpdds)); - do { // fake loop - // first attempt - res=(*pCreateDevice7)(lpd3d, Guid, lpdds, lplpd3dd); - if(res==DD_OK) break; // no error, break - OutTraceE("CreateDevice(D3D7) ERROR: err=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); - if(!(dxw.dwFlags1 & EMULATESURFACE)) break; // no more tricks .... - if(!(dxw.dwFlags1 & AUTOMATIC)) break; + res=(*pCreateDevice7)(lpd3d, Guid, lpdds, lplpd3dd); - //OutTraceD3D("CreateDevice(D3D7): SYSMEMORY OFF\n"); - //dxw.dwFlags5 |= NOSYSTEMEMULATED; - //res=(*pCreateDevice7)(lpd3d, Guid, lpdds, lplpd3dd); - //if(res==DD_OK) break; - //OutTraceE("CreateDevice(D3D7) ERROR: err=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); - //if(!(dxw.dwFlags1 & AUTOMATIC)) break; - - OutTraceD3D("CreateDevice(D3D7): Emulation OFF\n"); - //dxw.dwFlags5 &= ~NOSYSTEMEMULATED; - dxw.dwFlags1 &= ~EMULATESURFACE; - dxw.dwFlags1 |= LOCKEDSURFACE; - res=(*pCreateDevice7)(lpd3d, Guid, lpdds, lplpd3dd); - if(res==DD_OK) break; - OutTraceE("CreateDevice(D3D7) ERROR: err=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); - return res; - } while (FALSE); - if(res == DD_OK){ OutTraceD3D("CreateDevice(D3D7): lpd3dd=%x\n", lpd3d, *lplpd3dd); HookDirect3DDevice((void **)lplpd3dd, 7); } + else + OutTraceE("CreateDevice(D3D7) ERROR: err=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); return res; } diff --git a/dll/user32.cpp b/dll/user32.cpp index d447177..c142a16 100644 --- a/dll/user32.cpp +++ b/dll/user32.cpp @@ -618,8 +618,8 @@ BOOL WINAPI extInvalidateRect(HWND hwnd, RECT *lpRect, BOOL bErase) return (*pInvalidateRect)(hwnd, lpRect, bErase); } else{ - // just exagerate ... - return (*pInvalidateRect)(hwnd, NULL, bErase); + // don't exagerate ... + return (*pInvalidateRect)(hwnd, lpRect, bErase); } } @@ -1597,6 +1597,13 @@ HWND WINAPI extCreateWindowExW( } if(IsDebug) OutTrace("CreateWindowExW: DEBUG screen=(%d,%d)\n", 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); } @@ -1632,6 +1639,13 @@ HWND WINAPI extCreateWindowExA( } if(IsDebug) OutTrace("CreateWindowExA: DEBUG screen=(%d,%d)\n", 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); } @@ -1730,6 +1744,7 @@ int WINAPI extFillRect(HDC hdc, const RECT *lprc, HBRUSH hbr) return (*pFillRect)(hdc, &rc, hbr); } +#if 0 if(OBJ_DC == GetObjectType(hdc)){ if(rc.left < 0) rc.left = 0; if(rc.top < 0) rc.top = 0; @@ -1742,6 +1757,20 @@ int WINAPI extFillRect(HDC hdc, const RECT *lprc, HBRUSH hbr) res=(*pFillRect)(hdc, &rc, hbr); return res; +#else + { + HWND hwnd; + hwnd = WindowFromDC(hdc); + if(hwnd != dxw.GethWnd()){ + OutTraceDW("FillRect: unfixed rect\n"); + } + else { + dxw.MapClient(&rc); + } + } + res=(*pFillRect)(hdc, &rc, hbr); + return res; +#endif } int WINAPI extFrameRect(HDC hdc, const RECT *lprc, HBRUSH hbr) @@ -2052,6 +2081,31 @@ int WINAPI extGDIReleaseDC(HWND hwnd, HDC hDC) 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); @@ -2088,7 +2142,8 @@ HDC WINAPI extBeginPaint(HWND hwnd, LPPAINTSTRUCT lpPaint) if(!dxw.IsFullScreen()) return hdc; // on CLIENTREMAPPING, resize the paint area to virtual screen size - if(dxw.dwFlags1 & CLIENTREMAPPING) lpPaint->rcPaint=dxw.GetScreenRect(); + //if(dxw.dwFlags1 & CLIENTREMAPPING) lpPaint->rcPaint=dxw.GetScreenRect(); + if(dxw.dwFlags1 & CLIENTREMAPPING) dxw.UnmapClient(&(lpPaint->rcPaint)); switch(GDIEmulationMode){ case GDIMODE_STRETCHED: @@ -2149,6 +2204,7 @@ HWND WINAPI extCreateDialogIndirectParam(HINSTANCE hInstance, LPCDLGTEMPLATE lpT 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); @@ -2171,6 +2227,7 @@ HWND WINAPI extCreateDialogParam(HINSTANCE hInstance, LPCTSTR lpTemplateName, HW 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); @@ -2390,9 +2447,9 @@ int WINAPI extDrawTextA(HDC hdc, LPCTSTR lpchText, int nCount, LPRECT lpRect, UI OutTraceDW("DrawText: fixed rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); } - gFixed = TRUE; + gFixed = TRUE; ret=(*pDrawText)(hdc, lpchText, nCount, lpRect, uFormat); - gFixed=FALSE; + 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()); @@ -2430,7 +2487,7 @@ int WINAPI extDrawTextExA(HDC hdc, LPTSTR lpchText, int nCount, LPRECT lpRect, U gFixed = TRUE; ret=(*pDrawTextEx)(hdc, lpchText, nCount, lpRect, dwDTFormat, lpDTParams); - gFixed=FALSE; + gFixed = FALSE; if(nCount && !ret) OutTraceE("DrawTextEx: ERROR ret=%x err=%d\n", ret, GetLastError()); if (MustScale){ diff --git a/dll/user32.old.cpp b/dll/user32.old.cpp new file mode 100644 index 0000000..b43033f --- /dev/null +++ b/dll/user32.old.cpp @@ -0,0 +1,3099 @@ +#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" + +#define FIXCHILDSIZE FALSE + +BOOL IsChangeDisplaySettingsHotPatched = FALSE; +#define GDIMODE_STRETCHED 0 +#define GDIMODE_EMULATED 1 +int GDIEmulationMode = 0; +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); + +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_PTR (WINAPI *DialogBoxParamA_Type)(HINSTANCE, LPCTSTR, HWND, DLGPROC, LPARAM); +DialogBoxParamA_Type pDialogBoxParamA = NULL; +INT_PTR WINAPI extDialogBoxParamA(HINSTANCE, LPCTSTR, HWND, DLGPROC, LPARAM); + +#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_IAT_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_IAT_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, "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, "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)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_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_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 MouseHooks2[]={ + {HOOK_HOT_CANDIDATE, "SetCursorPos", (FARPROC)SetCursorPos, (FARPROC *)&pSetCursorPos, (FARPROC)extSetCursorPos}, + {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 +}; + +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 & MODIFYMOUSE) if (addr=RemapLibrary(proc, hModule, MouseHooks)) 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, MouseHooks2)) 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) +{ + GDIEmulationMode = GDIMODE_STRETCHED; // default + if (dxw.dwFlags2 & GDISTRETCHED) GDIEmulationMode = GDIMODE_STRETCHED; + if (dxw.dwFlags3 & GDIEMULATEDC) GDIEmulationMode = GDIMODE_EMULATED; + + 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 & MODIFYMOUSE) HookLibrary(hModule, MouseHooks, libname); + if (dxw.dwFlags1 & (PREVENTMAXIMIZE|FIXWINFRAME|LOCKWINPOS|LOCKWINSTYLE)) HookLibrary(hModule, WinHooks, libname); + if ((dxw.dwFlags1 & (MODIFYMOUSE|SLOWDOWN|KEEPCURSORWITHIN)) || (dxw.dwFlags2 & KEEPCURSORFIXED)) HookLibrary(hModule, MouseHooks2, 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); + HookLibInit(MouseHooks2); +} + +/* ------------------------------------------------------------------------------ */ +// 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; + + // 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(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(dxw.IsFullScreen() && dxw.IsRealDesktop(hwnd)) { + hwnd=dxw.GethWnd(); + dxw.MapClient(lpRect); + return (*pInvalidateRect)(hwnd, lpRect, bErase); + } + else{ + // just exagerate ... + return (*pInvalidateRect)(hwnd, NULL, 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); + + OutTraceDW("%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.... + 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){ + POINT cur; + RECT rect; + + // find window metrics + if (!(*pGetClientRect)(dxw.GethWnd(), &rect)) { + // report error and ignore ... + OutTraceE("GetClientRect(%x) ERROR %d at %d\n", dxw.GethWnd(), GetLastError(), __LINE__); + return 0; + } + + x= x * rect.right / dxw.GetScreenWidth(); + y= y * rect.bottom / dxw.GetScreenHeight(); + + // check for boundaries (???) + if (x >= rect.right) x=rect.right-1; + if (x<0) x=0; + if (y >= rect.bottom) y=rect.bottom-1; + if (y<0) y=0; + + // make it screen absolute + cur.x = x; + cur.y = y; + if (!(*pClientToScreen)(dxw.GethWnd(), &cur)) { + OutTraceE("ClientToScreen(%x) ERROR %d at %d\n", dxw.GethWnd(), GetLastError(), __LINE__); + return 0; + } + 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()); + 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)) return (*pGetDesktopWindow)(); + + OutTraceDW("GetDesktopWindow: FullScreen=%x\n", dxw.IsFullScreen()); + if (dxw.IsFullScreen()){ +#ifdef CREATEDESKTOP + if(CREATEDESKTOP){ + extern HWND hDesktopWindow; + OutTraceDW("GetDesktopWindow: returning desktop emulated hwnd=%x\n", hDesktopWindow); + return hDesktopWindow; + } +#endif + 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; + + pWindowProc = (WNDPROC)(*pGetWindowLongA)(hwnd, GWL_WNDPROC); + if((pWindowProc == extWindowProc) || + (pWindowProc == extChildWindowProc) || + (pWindowProc == extDialogWindowProc)){ // avoid recursions + HWND Father; + WNDPROC pFatherProc; + Father=GetParent(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; + +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; + } + +#ifdef CREATEDESKTOP + if(CREATEDESKTOP){ + extern HWND hDesktopWindow; + if (dxw.IsRealDesktop(hWndParent)){ + OutTraceE("%s: new parent win %x->%x\n", ApiName, hWndParent, hDesktopWindow); + hWndParent=hDesktopWindow; + } + } +#endif + + // 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. + 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 + ) + { + 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. + 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 { + // 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; + //} + 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; + } + + // tested on Gangsters: coordinates must be window-relative!!! + // Age of Empires.... + if (dwStyle & WS_CHILD){ + dxw.MapClient(&x, &y, &nWidth, &nHeight); + OutTraceDW("%s: fixed WS_CHILD pos=(%d,%d) size=(%d,%d)\n", + ApiName, x, y, nWidth, nHeight); + } + // needed for Diablo, that creates a new control parent window that must be + // overlapped to the directdraw surface. + else if (dwExStyle & WS_EX_CONTROLPARENT){ + dxw.MapWindow(&x, &y, &nWidth, &nHeight); + OutTraceDW("%s: fixed WS_EX_CONTROLPARENT 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); + } + + 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); + } + if(IsDebug) OutTrace("CreateWindowExW: DEBUG screen=(%d,%d)\n", dxw.GetScreenWidth(), dxw.GetScreenHeight()); + + if(!wcscmp(lpWindowName, L"ActiveMovie Window")){ + //x = y = 0; + RECT MainWin; + (*pGetClientRect)(dxw.GethWnd(), &MainWin); + //nWidth = dxw.GetScreenWidth(); + //nHeight = dxw.GetScreenHeight(); + 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); + } + if(IsDebug) OutTrace("CreateWindowExA: DEBUG screen=(%d,%d)\n", dxw.GetScreenWidth(), dxw.GetScreenHeight()); + + if(!strcmp(lpWindowName, "ActiveMovie Window")){ + //x = y = 0; + RECT MainWin; + (*pGetClientRect)(dxw.GethWnd(), &MainWin); + //nWidth = dxw.GetScreenWidth(); + //nHeight = dxw.GetScreenHeight(); + 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 !!! + HRESULT res; + + res = (HRESULT)-1; + if(hwnd == dxw.GethWnd()) res=FixWindowProc("DefWindowProcA", hwnd, Msg, wParam, &lParam); + + if (res==(HRESULT)-1) + return (*pDefWindowProcA)(hwnd, Msg, wParam, lParam); + else + return res; +} + +LRESULT WINAPI extDefWindowProcW(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + // v2.02.30: fix (Imperialism II): apply to main window only !!! + HRESULT res; + + res = (HRESULT)-1; + if(hwnd == dxw.GethWnd()) res=FixWindowProc("DefWindowProcW", hwnd, Msg, wParam, &lParam); + + if (res==(HRESULT)-1) + return (*pDefWindowProcW)(hwnd, Msg, wParam, lParam); + else + return res; +} + +int WINAPI extFillRect(HDC hdc, const RECT *lprc, HBRUSH hbr) +{ + int res; + RECT rc; + OutTraceDW("FillRect: hdc=%x hbrush=%x rect=(%d,%d)-(%d,%d)\n", hdc, hbr, lprc->left, lprc->top, lprc->right, lprc->bottom); + + if(dxw.dwFlags4 & NOFILLRECT) { + OutTraceDW("FillRect: SUPPRESS\n", hdc, hbr, lprc->left, lprc->top, lprc->right, lprc->bottom); + return TRUE; + } + + memcpy(&rc, lprc, sizeof(rc)); + + if(dxw.IsRealDesktop(WindowFromDC(hdc))) { + HWND VirtualDesktop; + VirtualDesktop=dxw.GethWnd(); + if(VirtualDesktop==NULL){ + OutTraceDW("FillRect: no virtual desktop\n"); + return TRUE; + } + OutTraceDW("FillRect: remapped hdc to virtual desktop hwnd=%x\n", dxw.GethWnd()); + hdc=(*pGDIGetDC)(dxw.GethWnd()); + } + + if(!dxw.IsFullScreen()) { + // 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("FillRect: remapped hdc from hwnd=%x to rect=(%d,%d)-(%d,%d)\n", hwnd, rc.left, rc.top, rc.right, rc.bottom); + return (*pFillRect)(hdc, &rc, hbr); + } + + 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); + //dxw.MapWindow(&rc); + OutTraceDW("FillRect: fixed rect=(%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom); + } + + res=(*pFillRect)(hdc, &rc, hbr); + return res; +} + +int WINAPI extFrameRect(HDC hdc, const RECT *lprc, HBRUSH hbr) +{ + int res; + RECT rc; + OutTraceDW("FrameRect: hdc=%x hbrush=%x rect=(%d,%d)-(%d,%d)\n", hdc, hbr, lprc->left, lprc->top, lprc->right, lprc->bottom); + + // when not in fullscreen mode, just proxy the call + if(!dxw.IsFullScreen()) return (*pFrameRect)(hdc, lprc, hbr); + + memcpy(&rc, lprc, sizeof(rc)); + 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("FrameRect: fixed rect=(%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom); + } + + res=(*pFrameRect)(hdc, &rc, hbr); + 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; + OutTraceDW("EnumDisplaySettings: Devicename=%s ModeNum=%x\n", lpszDeviceName, iModeNum); + res=(*pEnumDisplaySettings)(lpszDeviceName, iModeNum, lpDevMode); + 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; + } + } + 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()) 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) { + extern HDC hFlippedDC; + LPDIRECTDRAWSURFACE lpDDSPrim; + lpDDSPrim = dxwss.GetPrimarySurface(); + if (lpDDSPrim) (*pGetDC)(lpDDSPrim, &hFlippedDC); + 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; + offset.x >>= 2; + offset.y >>= 2; + dxw.UnmapClient(&offset); + OutTraceDW("%s: child window hwnd=%x offset=(%d,%d)\n", ApiName, hwnd, offset.x, offset.y); + (*pSetViewportOrgEx)(hFlippedDC, offset.x, offset.y, NULL); + } + OutTraceDW("%s: remapping flipped GDI lpDDSPrim=%x hdc=%x\n", ApiName, lpDDSPrim, hFlippedDC); + if(hFlippedDC) return hFlippedDC; + } + + switch(GDIEmulationMode){ + case GDIMODE_STRETCHED: + ret=(*pGDIGetDC)(lochwnd); + break; + case GDIMODE_EMULATED: + ret=dxw.AcquireEmulatedDC(lochwnd); + dxw.VirtualHDC=ret; + 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); + + if(bFlippedDC && (hDC == hFlippedDC)) { + 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 (ret) OutTraceE("GDI.ReleaseDC ERROR: err=%x(%s) at %d\n", ret, ExplainDDError(ret), __LINE__); + else dxw.ScreenRefresh(); + return (ret == DD_OK); + } + + switch(GDIEmulationMode){ + case GDIMODE_STRETCHED: + res=(*pGDIReleaseDC)(hwnd, hDC); + break; + case GDIMODE_EMULATED: + HDC windc; + windc=(*pGDIGetDC)(hwnd); + res=dxw.ReleaseEmulatedDC(hwnd); + res=(*pGDIReleaseDC)(hwnd, windc); + 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(); + + //if(bFlippedDC) { + // LPDIRECTDRAWSURFACE lpDDSPrim; + // lpDDSPrim = dxwss.GetPrimarySurface(); + // if (lpDDSPrim) (*pGetDC)(lpDDSPrim, &hFlippedDC); + // 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("GDI.BeginPaint: child window hwnd=%x offset=(%d,%d)\n", hwnd, offset.x, offset.y); + // (*pSetViewportOrgEx)(hFlippedDC, offset.x, offset.y, NULL); + // } + // OutTraceDW("GDI.BeginPaint: remapping flipped GDI lpDDSPrim=%x hdc=%x\n", lpDDSPrim, hFlippedDC); + // if(hFlippedDC) { + // lpPaint->hdc=hFlippedDC; + // return hFlippedDC; + // } + //} + + hdc=(*pBeginPaint)(hwnd, lpPaint); + + // if not in fullscreen mode, that's all! + if(!dxw.IsFullScreen()) return hdc; + + // on CLIENTREMAPPING, resize the paint area to virtual screen size + if(dxw.dwFlags1 & CLIENTREMAPPING) lpPaint->rcPaint=dxw.GetScreenRect(); + + switch(GDIEmulationMode){ + case GDIMODE_STRETCHED: + 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(bFlippedDC && hFlippedDC) { + // LPDIRECTDRAWSURFACE lpDDSPrim; + // lpDDSPrim = dxwss.GetPrimarySurface(); + // ret = DDERR_GENERIC; + // if (lpDDSPrim) ret=(*pReleaseDC)(lpDDSPrim, hFlippedDC); + // OutTraceDW("GDI.EndPaint: remapping flipped GDI lpDDSPrim=%x hdc=%x\n", lpDDSPrim, hFlippedDC); + + // //dxw.ScreenRefresh(); + // return (ret == DD_OK); + //} + + // if not fullscreen or not desktop win, just proxy the call + if(!dxw.IsFullScreen() || !dxw.Windowize){ + ret=(*pEndPaint)(hwnd, lpPaint); + return ret; + } + + // avoid access to real desktop + if(dxw.IsRealDesktop(hwnd)) hwnd=dxw.GethWnd(); + + switch(GDIEmulationMode){ + case GDIMODE_STRETCHED: + ret=(*pEndPaint)(hwnd, lpPaint); + break; + case GDIMODE_EMULATED: + ret=dxw.ReleaseEmulatedDC(hwnd); + 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(); + RetHWND=(*pCreateDialogIndirectParam)(hInstance, lpTemplate, hWndParent, lpDialogFunc, lParamInit); + dxw.SetFullScreen(FullScreen); + + // v2.02.73: redirect lpDialogFunc only when it is nor NULL + if(lpDialogFunc) { + 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(); + 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) { + 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()){ + 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; + POINT upleft = {0,0}; + (*pGetClientRect)(dxw.GethWnd(),&screen); + (*pClientToScreen)(dxw.GethWnd(),&upleft); + 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) +{ + 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.IsFullScreen() && (OBJ_DC == GetObjectType(hdc))){ + dxw.MapClient(&X, &Y); + 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; + BOOL MustScale; + 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); + + 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); + } + + 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); + } + + 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", + 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"); + } + + 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; + ret=(*pDrawTextEx)(hdc, lpchText, nCount, lpRect, dwDTFormat, lpDTParams); + gFixed=FALSE; + if(nCount && !ret) OutTraceE("DrawTextEx: ERROR ret=%x err=%d\n", ret, GetLastError()); + + if (MustScale){ + dxw.UnmapClient((RECT *)lpRect); + OutTraceDW("DrawTextEx: fixed output rect=(%d,%d)-(%d,%d)\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + + 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) +{ + OutTraceDW("RedrawWindow: hwnd=%x flags=%x\n", hWnd, flags); + return (*pRedrawWindow)(hWnd, lprcUpdate, hrgnUpdate, flags); +} + + +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.Windowize && 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; +HOOKPROC glpMessageHookProcessFunction; +/* +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; +} +*/ + +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 + 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; + } + } + 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); + OutTrace("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); + OutTrace("IsIconic: hwnd=%x ret=%x\n", hWnd, ret); + //return FALSE; + return ret; +} diff --git a/dll/winmm.cpp b/dll/winmm.cpp index 6d3b2d1..ea10616 100644 --- a/dll/winmm.cpp +++ b/dll/winmm.cpp @@ -115,6 +115,8 @@ MCIERROR WINAPI extmciSendCommand(mciSendCommand_Type pmciSendCommand, MCIDEVICE OutTraceDW("mciSendCommand: IDDevice=%x msg=%x(%s) Command=%x(%s)\n", IDDevice, uMsg, ExplainMCICommands(uMsg), fdwCommand, ExplainMCIFlags(uMsg, fdwCommand)); + if(dxw.dwFlags6 && BYPASSMCI) return 0; + if(dxw.IsFullScreen()){ switch(uMsg){ case MCI_WINDOW: diff --git a/host/TabDebug.cpp b/host/TabDebug.cpp index 040271f..01cd07a 100644 --- a/host/TabDebug.cpp +++ b/host/TabDebug.cpp @@ -42,7 +42,6 @@ void CTabDebug::DoDataExchange(CDataExchange* pDX) DDX_Check(pDX, IDC_NODDRAWBLT, cTarget->m_NoDDRAWBlt); DDX_Check(pDX, IDC_NODDRAWFLIP, cTarget->m_NoDDRAWFlip); DDX_Check(pDX, IDC_NOGDIBLT, cTarget->m_NoGDIBlt); - DDX_Check(pDX, IDC_NOFILLRECT, cTarget->m_NoFillRect); DDX_Check(pDX, IDC_ZBUFFERALWAYS, cTarget->m_ZBufferAlways); DDX_Check(pDX, IDC_HOTPATCHALWAYS, cTarget->m_HotPatchAlways); DDX_Check(pDX, IDC_FREEZEINJECTEDSON, cTarget->m_FreezeInjectedSon); diff --git a/host/TabDirectX.cpp b/host/TabDirectX.cpp index 6158799..c40c05e 100644 --- a/host/TabDirectX.cpp +++ b/host/TabDirectX.cpp @@ -27,7 +27,7 @@ void CTabDirectX::DoDataExchange(CDataExchange* pDX) CDialog::DoDataExchange(pDX); CTargetDlg *cTarget = ((CTargetDlg *)(this->GetParent()->GetParent())); DDX_Radio(pDX, IDC_AUTO, cTarget->m_DXVersion); - DDX_Radio(pDX, IDC_AUTOMATIC, cTarget->m_DxEmulationMode); + DDX_Radio(pDX, IDC_NOEMULATESURFACE, cTarget->m_DxEmulationMode); DDX_Radio(pDX, IDC_DDRAWFILTER, cTarget->m_DxFilterMode); DDX_Check(pDX, IDC_SUPPRESSCLIPPING, cTarget->m_SuppressClipping); DDX_Check(pDX, IDC_BLITFROMBACKBUFFER, cTarget->m_BlitFromBackBuffer); diff --git a/host/TabSysLibs.cpp b/host/TabSysLibs.cpp index 6e561a6..a0e8c11 100644 --- a/host/TabSysLibs.cpp +++ b/host/TabSysLibs.cpp @@ -32,6 +32,7 @@ void CTabSysLibs::DoDataExchange(CDataExchange* pDX) 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); // OpenGL DDX_Check(pDX, IDC_HOOKOPENGL, cTarget->m_HookOpenGL); // duplicated @@ -44,7 +45,9 @@ void CTabSysLibs::DoDataExchange(CDataExchange* pDX) // MCI DDX_Check(pDX, IDC_REMAPMCI, cTarget->m_RemapMCI); DDX_Check(pDX, IDC_NOMOVIES, cTarget->m_NoMovies); + DDX_Check(pDX, IDC_STRETCHMOVIES, cTarget->m_StretchMovies); DDX_Check(pDX, IDC_FIXMOVIESCOLOR, cTarget->m_FixMoviesColor); + DDX_Check(pDX, IDC_BYPASSMCI, cTarget->m_BypassMCI); // Kernel32 DDX_Radio(pDX, IDC_SONDEFAULT, cTarget->m_SonProcessMode); diff --git a/host/TargetDlg.cpp b/host/TargetDlg.cpp index 9cbddb8..3407cf3 100644 --- a/host/TargetDlg.cpp +++ b/host/TargetDlg.cpp @@ -22,7 +22,7 @@ CTargetDlg::CTargetDlg(CWnd* pParent /*=NULL*/) //{{AFX_DATA_INIT(CTargetDlg) m_DXVersion = 0; m_Coordinates = 0; - m_DxEmulationMode = 4; // default: AUTOMATIC + m_DxEmulationMode = 3; // default: emulated m_DxFilterMode = 0; // default: ddraw filtering m_DCEmulationMode = 0; // default: no emulation m_MouseVisibility = 0; @@ -127,6 +127,8 @@ CTargetDlg::CTargetDlg(CWnd* pParent /*=NULL*/) m_RemapMCI = TRUE; m_NoMovies = FALSE; m_FixMoviesColor = FALSE; + m_StretchMovies = FALSE; + m_BypassMCI = FALSE; m_SuppressRelease = FALSE; m_KeepCursorWithin = FALSE; m_KeepCursorFixed = FALSE; @@ -225,6 +227,7 @@ BOOL CTargetDlg::OnInitDialog() 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 diff --git a/host/TargetDlg.h b/host/TargetDlg.h index 3cdbf9c..3bceea0 100644 --- a/host/TargetDlg.h +++ b/host/TargetDlg.h @@ -50,7 +50,6 @@ public: BOOL m_ImportTable; BOOL m_RegistryOp; BOOL m_TraceHooks; - //BOOL m_HandleDC; BOOL m_UnNotify; BOOL m_Windowize; BOOL m_HotPatch; @@ -95,6 +94,8 @@ public: BOOL m_RemapMCI; BOOL m_NoMovies; BOOL m_FixMoviesColor; + BOOL m_StretchMovies; + BOOL m_BypassMCI; BOOL m_SuppressRelease; BOOL m_KeepCursorWithin; BOOL m_KeepCursorFixed; diff --git a/host/dxTabCtrl.h b/host/dxTabCtrl.h index 8a1a9d7..053db8e 100644 --- a/host/dxTabCtrl.h +++ b/host/dxTabCtrl.h @@ -16,7 +16,7 @@ class CDXTabCtrl : public CTabCtrl // Construction public: CDXTabCtrl(); - CDialog *m_tabPages[11]; + CDialog *m_tabPages[12]; // this must match the total number of tab elements! int m_tabCurrent; int m_nNumberOfPages; enum { IDD = IDC_TABPANEL }; diff --git a/host/dxwnd.ini b/host/dxwnd.ini new file mode 100644 index 0000000..018ba37 --- /dev/null +++ b/host/dxwnd.ini @@ -0,0 +1,38 @@ +[window] +exportpath=D:\DxWnd\exports.wip\ +posx=880 +posy=437 +sizx=320 +sizy=200 +[target] +title0=Star Trek Armada +path0=D:\Games\armada_demo\Armada.exe +launchpath0= +module0= +opengllib0= +notes0= +registry0=ciao\n +ver0=0 +coord0=0 +flag0=-2011168669 +flagg0=1543503872 +flagh0=98320 +flagi0=136314884 +flagj0=4224 +flagk0=327680 +tflag0=0 +initx0=0 +inity0=0 +minx0=0 +miny0=0 +maxx0=0 +maxy0=0 +posx0=100 +posy0=100 +sizx0=800 +sizy0=600 +maxfps0=0 +initts0=0 +winver0=0 +maxres0=-1 +swapeffect0=0 diff --git a/host/dxwndhost.aps b/host/dxwndhost.aps index 98ad216c2123fc91e3388465767e912b7993563e..50c8c15c84a35564c9df4dbcb89834e0473b077e 100644 GIT binary patch delta 4109 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 F{|^M*X3YQq diff --git a/host/dxwndhost.h b/host/dxwndhost.h index de5b35a..19688ed 100644 --- a/host/dxwndhost.h +++ b/host/dxwndhost.h @@ -30,8 +30,8 @@ typedef struct PRIVATEMAP { char title[MAX_TITLE+1]; char launchpath[MAX_PATH+1]; - char notes[MAX_NOTES+1]; - char registry[MAX_REGISTRY+1]; + char *notes; + char *registry; }PRIVATEMAP; ///////////////////////////////////////////////////////////////////////////// diff --git a/host/dxwndhost.rc b/host/dxwndhost.rc index 13040600061311a028d13031ed487ab9f3380430..bec4db029fa7451cb9bb3e4d0269cd5e9b285a28 100644 GIT binary patch delta 402 zcmZus&nts*9DY8=_HNB(m1Rpvq>ojNm35zqrMj> z?Vyz2?C?4$ZbU5ye*kAGa+Q3yv!26KPtWstp3k{qy)IY{CCkNZnlst%bMS~{7DuvBg2klkV zh7gp8boil3mT^9w?&6yXhcK#XU$$t_Oa22(2t8tr$Y=hlbV}l`gA~4eQrrIp8ef) ww2;&Ev{9#%kG|`9d&DaGbPDj#gNGYORq^7Zs2DpWhgsC=k^VKA(loR52Z=LrPyhe` delta 252 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

|DoNP2pA28q)P<%!#g$ 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 Z;p+0Ib?*I&LDqVTw3R5W$path) && (*c!='\\'); c--) *c=0; @@ -192,13 +195,13 @@ static void SetTargetFromDlg(TARGETMAP *t, CTargetDlg *dlg) if(dlg->m_MessagePump) t->flags5 |= MESSAGEPUMP; switch(dlg->m_DxEmulationMode){ - case 0: t->flags |= AUTOMATIC; break; - case 1: break; - case 2: t->flags |= EMULATEBUFFER; break; - case 3: t->flags |= LOCKEDSURFACE; break; - case 4: t->flags |= EMULATESURFACE; break; - case 5: t->flags5 |= HYBRIDMODE; break; - case 6: t->flags5 |= GDIMODE; break; + //case 0: t->flags |= AUTOMATIC; break; + case 0: break; + case 1: t->flags |= EMULATEBUFFER; break; + case 2: t->flags |= LOCKEDSURFACE; break; + case 3: t->flags |= EMULATESURFACE; break; + case 4: t->flags5 |= HYBRIDMODE; break; + case 5: t->flags5 |= GDIMODE; break; break; } @@ -324,6 +327,8 @@ static void SetTargetFromDlg(TARGETMAP *t, CTargetDlg *dlg) if(dlg->m_RemapMCI) t->flags5 |= REMAPMCI; if(dlg->m_NoMovies) t->flags6 |= NOMOVIES; if(dlg->m_FixMoviesColor) t->flags6 |= FIXMOVIESCOLOR; + if(dlg->m_StretchMovies) t->flags6 |= STRETCHMOVIES; + if(dlg->m_BypassMCI) t->flags6 |= BYPASSMCI; if(dlg->m_SuppressRelease) t->flags6 |= SUPPRESSRELEASE; if(dlg->m_KeepCursorWithin) t->flags |= KEEPCURSORWITHIN; if(dlg->m_KeepCursorFixed) t->flags2 |= KEEPCURSORFIXED; @@ -436,13 +441,13 @@ static void SetDlgFromTarget(TARGETMAP *t, CTargetDlg *dlg) dlg->m_NoWinPosChanges = t->flags5 & NOWINPOSCHANGES ? 1 : 0; dlg->m_MessagePump = t->flags5 & MESSAGEPUMP ? 1 : 0; - dlg->m_DxEmulationMode = 1; // none - if(t->flags & AUTOMATIC) dlg->m_DxEmulationMode = 0; - if(t->flags & EMULATEBUFFER) dlg->m_DxEmulationMode = 2; - if(t->flags & LOCKEDSURFACE) dlg->m_DxEmulationMode = 3; - if(t->flags & EMULATESURFACE) dlg->m_DxEmulationMode = 4; - if(t->flags5 & HYBRIDMODE) dlg->m_DxEmulationMode = 5; - if(t->flags5 & GDIMODE) dlg->m_DxEmulationMode = 6; + dlg->m_DxEmulationMode = 0; // none + //if(t->flags & AUTOMATIC) dlg->m_DxEmulationMode = 0; + if(t->flags & EMULATEBUFFER) dlg->m_DxEmulationMode = 1; + if(t->flags & LOCKEDSURFACE) dlg->m_DxEmulationMode = 2; + if(t->flags & EMULATESURFACE) dlg->m_DxEmulationMode = 3; + if(t->flags5 & HYBRIDMODE) dlg->m_DxEmulationMode = 4; + if(t->flags5 & GDIMODE) dlg->m_DxEmulationMode = 5; dlg->m_DxFilterMode = 0; if(t->flags4 & BILINEAR2XFILTER) dlg->m_DxFilterMode = 1; @@ -556,6 +561,8 @@ static void SetDlgFromTarget(TARGETMAP *t, CTargetDlg *dlg) dlg->m_RemapMCI = t->flags5 & REMAPMCI ? 1 : 0; dlg->m_NoMovies = t->flags6 & NOMOVIES ? 1 : 0; dlg->m_FixMoviesColor = t->flags6 & FIXMOVIESCOLOR ? 1 : 0; + dlg->m_StretchMovies = t->flags6 & STRETCHMOVIES ? 1 : 0; + dlg->m_BypassMCI = t->flags6 & BYPASSMCI ? 1 : 0; dlg->m_SuppressRelease = t->flags6 & SUPPRESSRELEASE ? 1 : 0; dlg->m_KeepCursorWithin = t->flags & KEEPCURSORWITHIN ? 1 : 0; dlg->m_KeepCursorFixed = t->flags2 & KEEPCURSORFIXED ? 1 : 0; @@ -642,6 +649,7 @@ static void SetDlgFromTarget(TARGETMAP *t, CTargetDlg *dlg) static void SaveConfigItem(TARGETMAP *TargetMap, PRIVATEMAP *PrivateMap, int i, char *InitPath) { char key[32], val[32]; + char *EscBuf = NULL; sprintf_s(key, sizeof(key), "title%i", i); WritePrivateProfileString("target", key, PrivateMap->title, InitPath); sprintf_s(key, sizeof(key), "path%i", i); @@ -653,9 +661,9 @@ static void SaveConfigItem(TARGETMAP *TargetMap, PRIVATEMAP *PrivateMap, int i, sprintf_s(key, sizeof(key), "opengllib%i", i); WritePrivateProfileString("target", key, TargetMap->OpenGLLib, InitPath); sprintf_s(key, sizeof(key), "notes%i", i); - WritePrivateProfileString("target", key, Escape(PrivateMap->notes), InitPath); + WritePrivateProfileString("target", key, Escape(PrivateMap->notes, &EscBuf), InitPath); sprintf_s(key, sizeof(key), "registry%i", i); - WritePrivateProfileString("target", key, Escape(PrivateMap->registry), InitPath); + WritePrivateProfileString("target", key, Escape(PrivateMap->registry, &EscBuf), InitPath); sprintf_s(key, sizeof(key), "ver%i", i); sprintf_s(val, sizeof(val), "%i", TargetMap->dxversion); WritePrivateProfileString("target", key, val, InitPath); @@ -729,6 +737,9 @@ static void SaveConfigItem(TARGETMAP *TargetMap, PRIVATEMAP *PrivateMap, int i, sprintf_s(key, sizeof(key), "swapeffect%i", i); sprintf_s(val, sizeof(val), "%i", TargetMap->SwapEffect); WritePrivateProfileString("target", key, val, InitPath); + + free(EscBuf); + EscBuf = NULL; } static void ClearTarget(int i, char *InitPath) @@ -796,70 +807,108 @@ static void ClearTarget(int i, char *InitPath) static int LoadConfigItem(TARGETMAP *TargetMap, PRIVATEMAP *PrivateMap, int i, char *InitPath) { char key[32]; + char *EscBuf = NULL; + char *sBuf; + sBuf = (char *)malloc(1000000); extern BOOL gbDebug; + // ------- sprintf_s(key, sizeof(key), "path%i", i); GetPrivateProfileString("target", key, "", TargetMap->path, MAX_PATH, InitPath); if(!TargetMap->path[0]) return FALSE; + // ------- sprintf_s(key, sizeof(key), "launchpath%i", i); GetPrivateProfileString("target", key, "", PrivateMap->launchpath, MAX_PATH, InitPath); + // ------- sprintf_s(key, sizeof(key), "title%i", i); GetPrivateProfileString("target", key, "", PrivateMap->title, sizeof(PRIVATEMAP)-1, InitPath); + // ------- sprintf_s(key, sizeof(key), "module%i", i); GetPrivateProfileString("target", key, "", TargetMap->module, sizeof(TargetMap->module)-1, InitPath); + // ------- sprintf_s(key, sizeof(key), "opengllib%i", i); GetPrivateProfileString("target", key, "", TargetMap->OpenGLLib, sizeof(TargetMap->OpenGLLib)-1, InitPath); + // ------- sprintf_s(key, sizeof(key), "notes%i", i); - GetPrivateProfileString("target", key, "", PrivateMap->notes, MAX_NOTES, InitPath); - strcpy(PrivateMap->notes, Unescape(PrivateMap->notes)); + GetPrivateProfileString("target", key, "", sBuf, 1000000, InitPath); + Unescape(sBuf, &EscBuf); + PrivateMap->notes = (char *)malloc(strlen(EscBuf)+1); + strcpy(PrivateMap->notes, EscBuf); + // ------- sprintf_s(key, sizeof(key), "registry%i", i); - GetPrivateProfileString("target", key, "", PrivateMap->registry, MAX_NOTES, InitPath); - strcpy(PrivateMap->registry, Unescape(PrivateMap->registry)); + GetPrivateProfileString("target", key, "", sBuf, 1000000, InitPath); + Unescape(sBuf, &EscBuf); + PrivateMap->registry = (char *)malloc(strlen(EscBuf)+1); + strcpy(PrivateMap->registry, EscBuf); + // ------- sprintf_s(key, sizeof(key), "ver%i", i); TargetMap->dxversion = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "coord%i", i); TargetMap->coordinates = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "flag%i", i); TargetMap->flags = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "flagg%i", i); TargetMap->flags2 = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "flagh%i", i); TargetMap->flags3 = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "flagi%i", i); TargetMap->flags4 = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "flagj%i", i); TargetMap->flags5 = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "flagk%i", i); TargetMap->flags6 = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "tflag%i", i); TargetMap->tflags = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "initx%i", i); TargetMap->initx = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "inity%i", i); TargetMap->inity = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "minx%i", i); TargetMap->minx = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "miny%i", i); TargetMap->miny = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "maxx%i", i); TargetMap->maxx = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "maxy%i", i); TargetMap->maxy = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "posx%i", i); TargetMap->posx = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "posy%i", i); TargetMap->posy = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "sizx%i", i); TargetMap->sizx = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "sizy%i", i); TargetMap->sizy = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "maxfps%i", i); TargetMap->MaxFPS = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "initts%i", i); TargetMap->InitTS = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "swapeffect%i", i); TargetMap->SwapEffect = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "winver%i", i); TargetMap->FakeVersionId = GetPrivateProfileInt("target", key, 0, InitPath); + // ------- sprintf_s(key, sizeof(key), "maxres%i", i); TargetMap->MaxScreenRes = GetPrivateProfileInt("target", key, 0, InitPath); @@ -867,8 +916,10 @@ static int LoadConfigItem(TARGETMAP *TargetMap, PRIVATEMAP *PrivateMap, int i, c // clear debug flags TargetMap->flags &= ~(0); TargetMap->flags3 &= ~(YUV2RGB|RGB2YUV|SURFACEWARN|ANALYTICMODE|NODDRAWBLT|NODDRAWFLIP|NOGDIBLT); - TargetMap->flags4 &= ~(NOFILLRECT); } + free(EscBuf); + EscBuf = NULL; + free(sBuf); return TRUE; } @@ -1161,14 +1212,16 @@ void CDxwndhostView::OnModify() pos = listctrl.GetFirstSelectedItemPosition(); i = listctrl.GetNextSelectedItem(pos); dlg.m_Title = PrivateMaps[i].title; - dlg.m_Notes = PrivateMaps[i].notes; - dlg.m_Registry = PrivateMaps[i].registry; + dlg.m_Notes = CString(PrivateMaps[i].notes); + dlg.m_Registry = CString(PrivateMaps[i].registry); dlg.m_LaunchPath = PrivateMaps[i].launchpath; SetDlgFromTarget(&TargetMaps[i], &dlg); if(dlg.DoModal() == IDOK && dlg.m_FilePath.GetLength()){ strnncpy(PrivateMaps[i].title, (char *)dlg.m_Title.GetString(), MAX_TITLE); - strnncpy(PrivateMaps[i].notes, (char *)dlg.m_Notes.GetString(), MAX_NOTES); - strnncpy(PrivateMaps[i].registry, (char *)dlg.m_Registry.GetString(), MAX_REGISTRY); + PrivateMaps[i].notes = (char *)realloc(PrivateMaps[i].notes, strlen(dlg.m_Notes.GetString())+1); + strcpy(PrivateMaps[i].notes, (char *)dlg.m_Notes.GetString()); + PrivateMaps[i].registry = (char *)realloc(PrivateMaps[i].registry, strlen(dlg.m_Registry.GetString())+1); + strcpy(PrivateMaps[i].registry, (char *)dlg.m_Registry.GetString()); strnncpy(PrivateMaps[i].launchpath, (char *)dlg.m_LaunchPath.GetString(), MAX_PATH); SetTargetFromDlg(&TargetMaps[i], &dlg); CListCtrl& listctrl = GetListCtrl(); @@ -1285,7 +1338,7 @@ void CDxwndhostView::OnSetRegistry() int i; CTargetDlg dlg; POSITION pos; - CString Registry; + char *Registry; FILE *regfp; CListCtrl& listctrl = GetListCtrl(); @@ -1301,7 +1354,7 @@ void CDxwndhostView::OnSetRegistry() return; } - fwrite(Registry.GetString(), Registry.GetLength(), 1, regfp); + fwrite(Registry, strlen(Registry), 1, regfp); fclose(regfp); } @@ -1551,8 +1604,10 @@ void CDxwndhostView::OnAdd() memset(&TargetMaps[i],0,sizeof(TARGETMAP)); // clean up, just in case.... if(dlg.DoModal() == IDOK && dlg.m_FilePath.GetLength()){ strnncpy(PrivateMaps[i].title, (char *)dlg.m_Title.GetString(), MAX_TITLE); - strnncpy(PrivateMaps[i].notes, (char *)dlg.m_Notes.GetString(), MAX_NOTES); - strnncpy(PrivateMaps[i].registry, (char *)dlg.m_Registry.GetString(), MAX_REGISTRY); + PrivateMaps[i].notes = (char *)malloc(strlen(dlg.m_Notes.GetString())+1); + strcpy(PrivateMaps[i].notes, (char *)dlg.m_Notes.GetString()); + PrivateMaps[i].registry = (char *)malloc(strlen(dlg.m_Registry.GetString())+1); + strcpy(PrivateMaps[i].registry, (char *)dlg.m_Registry.GetString()); strnncpy(PrivateMaps[i].launchpath, (char *)dlg.m_LaunchPath.GetString(), MAX_PATH); SetTargetFromDlg(&TargetMaps[i], &dlg); CListCtrl& listctrl = GetListCtrl(); diff --git a/host/resource b/host/resource index 47eb586ec14f0397eb96f59c0b409a10dba61792..561b289cf93f8698f666f583bb15f2d26b5fedf5 100644 GIT binary patch delta 89 zcmZ2ApXtE@rVSFAlMi?ZO-@MGn(UClHhGeyoT3v$Btrm$BSSC{`Z72(crtLpp&^42 mgX!dtWwM*4GA{^CzL23Zc|$eF