c# - .NET 运行时错误 80131506 - 将 Lambda 传递给 native 函数

标签 c# .net winapi garbage-collection pinvoke

所以我收到这个错误,看起来好像是一个损坏的垃圾收集:

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

完整的错误是:

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

它正在运行:

Framework Version: 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);

错误似乎只在我多次运行该方法后才会发生,但是,这种情况不会一直发生。有时有效,有时无效。

关于如何解决这个问题有什么建议吗?

最佳答案

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

问题是我将 lambda 作为委托(delegate)传递给 p/invoke:

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

因此,每次非托管 WinAPI 调用回调到我的委托(delegate)中时,GC 都有机会运行,如果运行的话,它会收集我的 lambda,从而导致这次崩溃。这不一定会发生,这就是为什么我的方法大部分时间都有效并且不一致地崩溃的原因。

解决方案是添加对 lambda 的引用,以防止 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;
        }

应用程序现在按预期运行。

关于c# - .NET 运行时错误 80131506 - 将 Lambda 传递给 native 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52360046/

相关文章:

c# - Microsoft .net,值得吗?

C# 通过 http 传输序列化 Protobuf 数据的最佳方式

c++ - 哪些因素会导致Win32错误665(文件系统限制)?

c# - JavaScriptSerializer 无法正确序列化 DynamicJsonObject

c# - Fiddler 根据请求向 WCF 服务 PUT/POST 提供 411 错误

c# - 如何保证Socket发送的数据?

c# - 有什么方法可以检测 .NET 中的 RTL 语言吗?

c - 来自默认 WndProc 内部的嵌套调用

c++ - 让两个窗口毫不拖延地粘在一起

c# - Entity Framework 重复对象和所有子属性