Per*_*nce 5 .net c# pinvoke winapi garbage-collection
所以我收到这个错误,看起来好像是一个损坏的垃圾回收:
完整的错误是:
由于.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;
}
Run Code Online (Sandbox Code Playgroud)
其中FindWindowEx(),EnumChildWindows()并且GetWindowText()都的P / Invoke签名定义类似于此:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
Run Code Online (Sandbox Code Playgroud)
在我多次运行该方法后,似乎只会出现该错误,但是这种情况并不会一直发生。有时它起作用,有时却不起作用。
对于如何解决这个问题,有任何的建议吗?
因此,我在Discord的慷慨捐助者的帮助下解决了我的问题。
问题是我将a Lamda作为代理传递给ap / invoke:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
Run Code Online (Sandbox Code Playgroud)
因此,每次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;
}
Run Code Online (Sandbox Code Playgroud)
该应用程序现在可以按预期工作。