visit
Jumping forward several years, I wanted to give the old game another play. I knew the graphics wouldn't hold up but to play in its nostalgic sandbox would more than overcome that. I installed the game and the various patches, modified configuration files to use my monitor's native resolution (1080p), and tried to launch it. Unfortunately, it wouldn't launch at all.
I'm back on my desktop.
For the sharp-eyed individuals, you might notice that this is actually playing through - this is part of . It actually plays great (no noticeable input lag) via Parsec, over Wi-Fi, from my desktop to my laptop. That said, I did try the game directly on that machine and it still crashed so something else was to blame.
So what would any good programmer do? Search for an existing solution online. Write their own program to fix it!
//A snippet of the code that helped me with the Win32 APIs from the Simple Runtime Window Editor (SRWE)
//Source: //github.com/dtgDTGdtg/SRWE/blob/b439859e15ca44b6c4715fdb015c321a49ef634a/SRWE/Window.cs
public void RemoveBorders()
{
uint nStyle = (uint)WinAPI.GetWindowLong(m_hWnd, WinAPI.GWL_STYLE);
nStyle = (nStyle | (WinAPI.WS_THICKFRAME + WinAPI.WS_DLGFRAME + WinAPI.WS_BORDER)) ^ (WinAPI.WS_THICKFRAME + WinAPI.WS_DLGFRAME + WinAPI.WS_BORDER);
WinAPI.SetWindowLong(m_hWnd, WinAPI.GWL_STYLE, nStyle);
nStyle = (uint)WinAPI.GetWindowLong(m_hWnd, WinAPI.GWL_EXSTYLE);
nStyle = (nStyle | (WinAPI.WS_EX_DLGMODALFRAME + WinAPI.WS_EX_WINDOWEDGE + WinAPI.WS_EX_CLIENTEDGE + WinAPI.WS_EX_STATICEDGE)) ^ (WinAPI.WS_EX_DLGMODALFRAME + WinAPI.WS_EX_WINDOWEDGE + WinAPI.WS_EX_CLIENTEDGE + WinAPI.WS_EX_STATICEDGE);
WinAPI.SetWindowLong(m_hWnd, WinAPI.GWL_EXSTYLE, nStyle);
uint uFlags = WinAPI.SWP_NOSIZE | WinAPI.SWP_NOMOVE | WinAPI.SWP_NOZORDER | WinAPI.SWP_NOACTIVATE | WinAPI.SWP_NOOWNERZORDER | WinAPI.SWP_NOSENDCHANGING | WinAPI.SWP_FRAMECHANGED;
WinAPI.SetWindowPos(m_hWnd, 0, 0, 0, 0, 0, uFlags);
}
WM_EXITSIZEMOVE
to the window, a tip from - never checked if it was strictly necessary for BF1942 though)
After doing a rough integration with pieces from that codebase, I gave it a run and... my application crashed. I was using process.MainWindowHandle
to get BF1942's game window. Turns out that it isn't set till, well, there is a main window available. So I wrote some code to wait for that and bingo - it launched the game and worked!
unsafe static void UpdateWindowPosition(int handle)
{
var info = new WINDOWINFO();
var success = WinAPI.GetWindowInfo(handle, ref info);
if (success)
{
var windowDimensions = info.rcWindow;
var monitorHandle = WinAPI.MonitorFromWindow(handle, 0);
var monitorInfo = new LPMONITORINFO
{
cbSize = (uint)sizeof(LPMONITORINFO)
};
WinAPI.GetMonitorInfoA(monitorHandle, ref monitorInfo);
var monitorDimensions = monitorInfo.rcMonitor;
var x = monitorDimensions.Width / 2 - windowDimensions.Width / 2;
var y = monitorDimensions.Height / 2 - windowDimensions.Height / 2;
SetPosition(handle, x, y);
}
}
static void SetPosition(int handle, int x, int y)
{
uint uFlags = WinAPI.SWP_NOSIZE | WinAPI.SWP_NOZORDER | WinAPI.SWP_NOACTIVATE | WinAPI.SWP_NOOWNERZORDER | WinAPI.SWP_NOSENDCHANGING | WinAPI.SWP_FRAMECHANGED;
WinAPI.SetWindowPos(handle, WinAPI.HWND_TOPMOST, x, y, 0, 0, uFlags);
WinAPI.SendMessage(handle, WinAPI.WM_EXITSIZEMOVE, 0, 0);
}
static void UpdateWindowPosition(Window window)
{
var monitorBounds = window.GetCurrentMonitor().GetBounds();
var windowBounds = window.GetBounds();
var x = monitorBounds.Width / 2 - windowBounds.Width / 2;
var y = monitorBounds.Height / 2 - windowBounds.Height / 2;
window.SetPosition(x, y);
}
The way I went about achieving my desired interface to the Win32 APIs I needed was via creating record-struct wrappers around the various native handles and having instance methods wrap the API calls themselves. For example, below is my Window
type that I have most of my functionality hanging off of.
public readonly record struct Window(nint Handle)
{
private HWND Win32Handle => new(Handle);
public Monitor GetCurrentMonitor()
{
nint handle = PInvoke.MonitorFromWindow(Win32Handle, 0);
return new(handle);
}
public void SetPosition(int x, int y)
{
var flags = SET_WINDOW_POS_FLAGS.SWP_NOSIZE | SET_WINDOW_POS_FLAGS.SWP_NOZORDER | SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE |
SET_WINDOW_POS_FLAGS.SWP_NOOWNERZORDER | SET_WINDOW_POS_FLAGS.SWP_NOSENDCHANGING | SET_WINDOW_POS_FLAGS.SWP_FRAMECHANGED;
PInvoke.SetWindowPos(Win32Handle, PInvoke.HWND_TOPMOST, x, y, 0, 0, flags);
PInvoke.SendMessage(Win32Handle, PInvoke.WM_EXITSIZEMOVE, default, default);
}
public Rectangle GetBounds()
{
var windowInfo = new WINDOWINFO();
PInvoke.GetWindowInfo(Win32Handle, ref windowInfo);
return Rectangle.From(windowInfo.rcWindow);
}
public void RemoveBorders()
{
var style = PInvoke.GetWindowLong(Win32Handle, WINDOW_LONG_PTR_INDEX.GWL_STYLE);
style &= ~(int)(WINDOW_STYLE.WS_THICKFRAME | WINDOW_STYLE.WS_DLGFRAME | WINDOW_STYLE.WS_BORDER);
_ = PInvoke.SetWindowLong(Win32Handle, WINDOW_LONG_PTR_INDEX.GWL_STYLE, style);
style = PInvoke.GetWindowLong(Win32Handle, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
style &= ~(int)(WINDOW_EX_STYLE.WS_EX_DLGMODALFRAME | WINDOW_EX_STYLE.WS_EX_WINDOWEDGE | WINDOW_EX_STYLE.WS_EX_CLIENTEDGE | WINDOW_EX_STYLE.WS_EX_STATICEDGE);
_ = PInvoke.SetWindowLong(Win32Handle, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, style);
PInvoke.SendMessage(Win32Handle, PInvoke.WM_EXITSIZEMOVE, default, default);
}
}
I called my project Borderless 1942 which . It is a self-contained, single-file .NET 6 application. Because it is self-contained, you don't need .NET 6 installed to run it.