问题
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?
回答1:
So I solved my issue with the help of a generous benefactor on Discord.
The problem was that I was passing a Lamda
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 lamda 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 lamda 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.
来源:https://stackoverflow.com/questions/52360046/net-runtime-error-80131506-passing-lambda-to-native-function