I'm writing a cross-platform emulator frontend using Eto.Forms in C#. The emulator backend requires a native window to display its output to, and thus, I need to write native controls wrapping said native windows.
To create a WinAPI window, I need to create and register a window class, which I do like this (imports and static imports removed for clarity):
static unsafe Win32SubWindow()
{
_refWndProc = WindowProc;
fixed (char* pWindowClass = WINDOW_CLASS)
{
WNDCLASSEXW wndClass = new()
{
cbSize = (uint) Marshal.SizeOf<WNDCLASSEXW>(),
style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
lpfnWndProc = _refWndProc,
cbClsExtra = 0,
cbWndExtra = 0,
hInstance = CurrentHInstanceRaw,
hIcon = HICON.Null,
hCursor = LoadCursor(HINSTANCE.Null, IDC_ARROW),
hbrBackground = HBRUSH.Null,
lpszMenuName = null,
lpszClassName = pWindowClass,
hIconSm = HICON.Null
};
RegisterClassEx(in wndClass);
}
}
internal static readonly WNDPROC _refWndProc;
The _refWndProc
variable should keep the delegate alive until the program ends, but I'm met with this error when I close my window:
Process terminated. A callback was made on a garbage collected delegate of type 'M64RPFW.Wpf!Windows.Win32.UI.WindowsAndMessaging.WNDPROC::Invoke'.
Repeat 3 times:
--------------------------------
at MS.Win32.UnsafeNativeMethods.CallWindowProc(IntPtr, IntPtr, Int32, IntPtr, IntPtr)
at MS.Win32.UnsafeNativeMethods.CallWindowProc(IntPtr, IntPtr, Int32, IntPtr, IntPtr)
at MS.Win32.HwndSubclass.DefWndProcWrapper(IntPtr, Int32, IntPtr, IntPtr)
at MS.Win32.UnsafeNativeMethods.CallWindowProc(IntPtr, IntPtr, Int32, IntPtr, IntPtr)
at MS.Win32.UnsafeNativeMethods.CallWindowProc(IntPtr, IntPtr, Int32, IntPtr, IntPtr)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr)
--------------------------------
at MS.Win32.UnsafeNativeMethods.DispatchMessage(System.Windows.Interop.MSG ByRef)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(System.Windows.Interop.MSG ByRef)
at System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame)
at System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunDispatcher(System.Object)
at System.Windows.Application.RunInternal(System.Windows.Window)
at System.Windows.Application.Run(System.Windows.Window)
at Eto.Wpf.Forms.ApplicationHandler.Run()
at Eto.Forms.Application.Run()
at M64PRR.Wpf.Program.Main(System.String[])
What could cause Win32SubWindow._refWndProc
to be garbage-collected while it is still in use? Other SO questions I've found have been solved by maintaining a reference to the delegate.
CodePudding user response:
The error was caused by a different instance of WNDPROC
than the one mentioned here. My application also uses a helper window to help initialize OpenGL, and moving that window's WNDPROC
to a variable solved the issue.