.NET Runtime Error 80131506 - Passing Lambda to Native Function
Asked Answered
W

1

8

So I'm getting this error that looks as though it's a corrupted garbage collection:

Application Crashes With "Internal Error In The .NET Runtime"

The full error is:

The process was terminated due to an internal error in the .NET Runtime at IP 71C571C8 (71B20000) with exit code 80131506.

It's running on:

Framework Version: v4.0.30319

This occurs inconsistently when running this function repeatedly:

        public static int GetMdiTitledChildWindows(IntPtr parentWindow)
        {
            IntPtr mdiClient = FindWindowEx(parentWindow, IntPtr.Zero, MdiClient, "");
            List<IntPtr> handles = new List<IntPtr>();
            EnumChildWindows(mdiClient, (hwnd, param) =>
            {
                handles.Add(hwnd);
                return true;
            }, IntPtr.Zero);
            int counter = 0;
            foreach (IntPtr handle in handles)
            {
                StringBuilder builder = new StringBuilder();
                GetWindowText(handle, builder, GetWindowTextLength(handle)+1);
                if (builder.Length > 0)
                {
                    counter++;
                }
            }
            return counter;
        }

Where FindWindowEx(), EnumChildWindows() and GetWindowText() are all p/invoke signatures defined similarly to this:

[DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);

The error only seems to occur after I've run the method many times, however, this doesn't happen consistently. Sometimes it works, sometimes it doesn't.

Any suggestions on how to fix this?

Wore answered 17/9, 2018 at 2:23 Comment(2)
Isn't this a duplicate of the question you've linked?Intracranial
@orangedog I don't believe so because as far as I can tell the issue in the question I've linked was caused by concurrent garbage collection not by passing a lamdaWore
W
10

So I solved my issue with the help of a generous benefactor on Discord.

The problem was that I was passing a lambda to a p/invoke as a delegate:

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);

So every time the unmanaged WinAPI call called-back into my delegate, the GC had the opportunity to run, if it did, it collected my lambda causing this crash. This wouldn't necessarily happen, hence why my method worked most of the time and crashed inconsistently.

The solution was to add a reference to the lambda that would prevent the GC from collecting it (although I went whole-hog and made it a local function because belt and braces):

        public static int GetMdiTitledChildWindows(IntPtr parentWindow)
        {
            IntPtr mdiClient = FindWindowEx(parentWindow, IntPtr.Zero, MdiClient, "");
            List<IntPtr> handles = new List<IntPtr>();
            bool addToList(IntPtr hwnd, IntPtr param)
            {
                handles.Add(hwnd);
                return true;
            }
            EnumWindowsProc gcHolder = addToList;
            EnumChildWindows(mdiClient, gcHolder, IntPtr.Zero);
            int counter = 0;
            foreach (IntPtr handle in handles)
            {
                int textLength = GetWindowTextLength(handle) + 1;
                StringBuilder builder = new StringBuilder(textLength);
                GetWindowText(handle, builder, textLength);
                if (builder.Length > 0)
                {
                    counter++;
                }
            }
            return counter;
        }

The application now works as expected.

Wore answered 17/9, 2018 at 3:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.