Piszę małą aplikację w C # za pomocą P / Invoke, aby utworzyć okno. Dostaję System.ExecutionEngineException rzucony przez PeekMessage podczas pracy z dużymi tablicami. Jest to dziwne, ponieważ faktycznie pracuję z tablicami, nie wyrzucane są wyjątki i wszystko jest w porządku. Ale kiedy dzwonię PeekMessage ona rzuca. Nie tworząc tablicy zapobiegających wydarzeniu problemu. Po wystąpieniu wyjątku jest to drukowane do konsoli:

Process terminated. A callback was made on a garbage collected delegate of type 'PInvoke.User32!PInvoke.User32+WndProc::Invoke'.
   at PInvoke.User32.PeekMessage(MSG*, IntPtr, WindowMessage, WindowMessage, PeekMessageRemoveFlags)
   at PInvoke.User32.PeekMessage(MSG*, IntPtr, WindowMessage, WindowMessage, PeekMessageRemoveFlags)
   at PInvoke.User32.PeekMessage(IntPtr, IntPtr, WindowMessage, WindowMessage, PeekMessageRemoveFlags)
   at Program.Main(System.String[])

Byłem w stanie spiętkować małą próbkę poniżej mojego projektu, który odtwarza błąd. Używam .NET Core 3.1.

using System;
using System.Drawing;
using static PInvoke.Kernel32;
using static PInvoke.User32;

static class Program
{
    static IntPtr HWND;

    static unsafe void Main(string[] args)
    {
        // creating the arrays on lines 14, 16, and 26 somehow cause the error and creating the window after line 18 doesn't cause the error.

        HWND = CreateWindow();

        byte[] b = new byte[100000000];

        DoSomething(new int[10000]);

        PeekMessage(HWND, HWND, 0, 0, PeekMessageRemoveFlags.PM_REMOVE);
    }

    public static void DoSomething(int[] data)
    {
        Color[] result = new Color[data.Length];
    }

    static unsafe IntPtr WndProc(IntPtr hwnd, WindowMessage msg, void* wParam, void* lParam)
    {
        return DefWindowProc(hwnd, msg, (IntPtr)wParam, (IntPtr)lParam);
    }

    static unsafe IntPtr CreateWindow()
    {
        var hIsnt = GetModuleHandle(null);

        string classname = "test";
        WNDCLASS wndclass;

        fixed (char* pClassName = classname)
            wndclass = new WNDCLASS()
            {
                lpfnWndProc = WndProc,
                hInstance = hIsnt.DangerousGetHandle(),
                lpszClassName = pClassName
            };

        RegisterClass(ref wndclass);

        var hwnd = PInvoke.User32.CreateWindow(
            classname,
            "test",
            WindowStyles.WS_CAPTION |
            WindowStyles.WS_VISIBLE,
            100, 100, 1280, 720,
            IntPtr.Zero, IntPtr.Zero,
            hIsnt.DangerousGetHandle(),
            IntPtr.Zero
            );

        return hwnd;
    }

    static unsafe void HandleEvents()
    {
        MSG msg;
        while (PeekMessage(&msg, HWND, 0, 0, PeekMessageRemoveFlags.PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
}

Klugnowałbym jakąkolwiek pomoc, którą możesz zaoferować!

1
Redninja1061 18 październik 2020, 23:41

1 odpowiedź

Najlepsza odpowiedź

Mam to! Problem polegał na tym, że Delegat WNDPROC przekazany do niezarządzanego kodu był uwolniony przez GC, a stosowanie dużych tablic powodował zbieranie śmieci. Prosta poprawka była utrzymywanie odniesienia Delegat WNDPROC przekazany do klasy okna.

1
Redninja1061 18 październik 2020, 23:41