.NET 运行时错误 80131506 - 将 Lambda 传递给本机函数
.NET Runtime Error 80131506 - Passing Lambda to Native Function
所以我收到这个错误,看起来好像是损坏的垃圾收集:
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 上一位慷慨的捐助者的帮助下解决了我的问题。
问题是我将 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;
}
该应用程序现在按预期运行。
所以我收到这个错误,看起来好像是损坏的垃圾收集:
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 上一位慷慨的捐助者的帮助下解决了我的问题。
问题是我将 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;
}
该应用程序现在按预期运行。