.NET运行时错误80131506-将Lambda传递给本机函数

时间:2018-09-17 02:23:56

标签: c# .net winapi garbage-collection pinvoke

所以我收到了一个看起来好像是垃圾回收已损坏的错误:

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

完整错误是:

  

由于.NET运行时IP 71C571C8(71B20000)出现内部错误,退出代码80131506,该过程被终止。

它正在运行:

  

框架版本:v4.0.30319

当重复运行此功能时,这种情况会不一致地出现:

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;
        }

FindWindowEx()EnumChildWindows()GetWindowText()都是p / invoke签名,其定义与此类似:

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

该错误似乎仅在我多次运行该方法之后才会发生,但是,这种情况并不会一直发生。有时候它有用,有时候却没有。

关于如何解决此问题的任何建议?

1 个答案:

答案 0 :(得分:3)

所以我在Discord的慷慨捐助者的帮助下解决了我的问题。

问题是我正在将Lamda作为委托传递给p / invoke:

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

因此,每次unmanaged WinAPI回调回我的委托人时,GC都有机会运行,如果这样做,它将收集我的lamda导致崩溃。这不一定会发生,因此为什么我的方法在大多数情况下都有效并且崩溃不一致。

解决方案是添加对lamda的引用,以防止GC收集它(尽管我是全猪,由于皮带和花括号而使其成为局部函数):

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;
        }

该应用程序现在可以正常运行了。