I haven’t posted much the past months due to my work commitment and the fact that the stuff I’m working on currently requires a lot of explanation and thus time to create the posts. I hope I can get some posts out during my winter vacation though!
Anyway, last weekend when I was recording some IV footage I found it unbelievable inconvenient I had to remove the “-windowed” switch and restart the game when I wanted to go fullscreen. Also I couldn’t simply go back to windowed mode then, which was annoying as well, since the fullscreen mode of IV is not known to be very ALT-TAB friendly…
So I thought it would be nice to have a simple fullscreen <–> windowed mode switch. Judging from my recent DX 11 experience I was sure it would be really simple, as it doesn’t involve more than a single call to SetFullscreenState. It turned out it’s more difficult on DX 9 though. Here’s how I finally realized it (research based on EFLC 188.8.131.52 as always):
Finding the windowed code
Okay so we know there is code to make the game windowed at startup due ot the “-windowed” commandline switch. So that’s a good way to start. A simple string search for “windowed” yielded good results: [GRAPHICS] Force windowed mode
Following that led us to the commandline switch we were seeking. Doing an xref in IDA eventually led to this piece of code (without the names usually of course):
.text:007D77DE 048 mov g_cmdarg_fullscreenMode.m_pszValue, offset aFullscreen ; "fullscreen" .text:007D77E8 048 mov g_cmdarg_windowedMode.m_pszValue, esi .text:007D77EE 048 mov g_bSettingsIsFullscreenMode, eax
Followed by API calls to SetWindowLongA and SetWindowPos this seemed like the right place. Especially the call below is very interesting:
.text:007D77FF 058 call GetScreenSettings
After some analysis it turns out it writes width, height and whether the game should run in fullscreen mode to the variables pushed. We also find bSettingsIsFullscreenMode
being used in that function again. At that time I went in-game to the graphics menu, changed the value of bSettingsIsFullscreenMode in memory and hit Space to apply changes. And it worked: So simple, yet effective!
Manually resetting the d3d device
However it still required us to go in the menu and choose to save changes, which is not as convenient as a simple ALT+Enter anytime during gameplay. Now we had to manually call the code resetting our d3d device and applying the changes. I decided to set a breakpoint on GetScreenSettings and went into the graphics menu again (and saved) just to find it being called from
.text:00480B4D 034 call GetScreenSettings
A more in-depth analysis of this function turned out it is responsible for the graphics menu and only called when you select the Graphics tab in the game menu. Furthermore, once you hit Space, the code at 00480AB3 is called. So by utilizing this code part I was able to reset the d3d device and reflect the change I made to bSettingsIsFullscreenMode. Simple as that!
The next LCPDFR release will contain this function, I hope you find it as useful as I do.