raylib-extras/rlImGui-cs

Clipboard delegates getting garbage collected.

Closed this issue · 1 comments

rlImGui-cs 2.0.3
Raylib-cs 6.1.1
ImGui.NET 1.90.8.1
.NET 8.0.300
OS Name Microsoft Windows 11 Pro
OS Version 10.0.22631

Pressing CTRL-C or CTRL-V inside of InputTextMultiline usually causes the application to crash with a System.ExecutionEngineException while debugging. It happens less frequently on InputText.

The application crash while executing from a console produces the following:

Process terminated. A callback was made on a garbage collected delegate of type 'rlImGui!rlImGui_cs.rlImGui+SetClipTextCallback::Invoke'.
Repeat 2 times:
--------------------------------
   at ImGuiNET.ImGuiNative.igInputTextMultiline(Byte*, Byte*, UInt32, System.Numerics.Vector2, ImGuiNET.ImGuiInputTextFlags, ImGuiNET.ImGuiInputTextCallback, Void*)
--------------------------------
   at ImGuiNET.ImGui.InputTextMultiline(System.String, System.String ByRef, UInt32, System.Numerics.Vector2, ImGuiNET.ImGuiInputTextFlags, ImGuiNET.ImGuiInputTextCallback, IntPtr)
   at ImGuiNET.ImGui.InputTextMultiline(System.String, System.String ByRef, UInt32, System.Numerics.Vector2)
   at Nickel.AI.Desktop.UI.ChatPanel.DoRender()

This seems to occur because the delegates are defined within the EndInitImGui method starting here

            // copy/paste callbacks
            unsafe
            {
                GetClipTextCallback getClip = new GetClipTextCallback(rImGuiGetClipText);
                SetClipTextCallback setClip = new SetClipTextCallback(rlImGuiSetClipText);

                io.SetClipboardTextFn = Marshal.GetFunctionPointerForDelegate(setClip);
                io.GetClipboardTextFn = Marshal.GetFunctionPointerForDelegate(getClip);
            }

I was able to resolve this issue by redefining those callbacks in my application as member variables. My copy/paste/modify solution, that is called after rlImGui.Setup, is as follows:

    unsafe internal static sbyte* rImGuiGetClipText(IntPtr userData)
    {
        return Raylib.GetClipboardText();
    }

    unsafe internal static void rlImGuiSetClipText(IntPtr userData, sbyte* text)
    {
        Raylib.SetClipboardText(text);
    }

    private unsafe delegate sbyte* GetClipTextCallback(IntPtr userData);
    private unsafe delegate void SetClipTextCallback(IntPtr userData, sbyte* text);

    private unsafe static GetClipTextCallback getClip = new GetClipTextCallback(rImGuiGetClipText);
    private unsafe static SetClipTextCallback setClip = new SetClipTextCallback(rlImGuiSetClipText);

    private static void SetupClipboard()
    {
        ImGuiIOPtr io = ImGui.GetIO();
        unsafe
        {
            io.SetClipboardTextFn = Marshal.GetFunctionPointerForDelegate(setClip);
            io.GetClipboardTextFn = Marshal.GetFunctionPointerForDelegate(getClip);
        }
    }

A fix for this has been pushed up and is part of the 2.1.0 nuget package.