Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception thrown in managed DLL is not handled properly #85

Closed
Olby2000 opened this issue Sep 27, 2018 · 3 comments
Closed

Exception thrown in managed DLL is not handled properly #85

Olby2000 opened this issue Sep 27, 2018 · 3 comments
Labels

Comments

@Olby2000
Copy link

Olby2000 commented Sep 27, 2018

Hi,
This is not as much an issue with the dllexport it self as with how the produced libraries work within a C++ host.

Basically I wrote an extension DLL for an un-managed C++ application. Everything works great, however when an exception is thrown in the managed code (e.g. throw new Exception();) the calling thread is terminated before any of the catch block code is executed. VS debugger will say something like The thread 0x3d8 has exited with code 0 (0x0). and anything I do in the catch block like calling hosts's API commands, displaying a message box or log the error will not work because the host application has moved on and the debugger will display Exception thrown: 'System.NullReferenceException' in ManagedPlugin.dll

Any ideas how to fix this? Thank you.

@3F 3F added the question label Sep 28, 2018
@3F
Copy link
Owner

3F commented Sep 28, 2018

You have many ways. For example, for SEH handling more like:

unmanaged C++

int filter(unsigned int code, struct _EXCEPTION_POINTERS* ptr) { 
    ... 
    return EXCEPTION_EXECUTE_HANDLER; 
}
...

__try
{
    lib.call<int>("ThrowUnhandledCLRException");
}
__except(filter(GetExceptionCode(), GetExceptionInformation()))
{
    //... yey!
}

However, I recommend wrapping for CLR side. If pointwise is difficult to cover lot of procs, well, you can also try with ~GetLastError model through wrapping all unhandled exceptions via existing domains, for example:

~

C#

AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) =>
{
    SetLastError(
        ...
    );
};

unmanaged C++

try
{
    ...
    throwIfError();
}
catch(const UnhandledCLRException& ex)
{
    ...
}

Or some other pre-processing via CLR side.

etc.

@Olby2000
Copy link
Author

Olby2000 commented Oct 1, 2018

My bad! It was a silly typo :) In my catch block I had this:

[DllExport(CallingConvention = CallingConvention.StdCall)]
public static uint Test()
{
	try
	{
		MessageBox.Show("test1"); // ok
		throw new Exception();
	}
	catch (Exception e)
	{
		MessageBox.Show($"{e.Message}" +
			$"\n{e.InnerException.Message}"); // fails here
		return 1;
	}
	return 0;
}

The $"\n{e.InnerException.Message}"); // fails here line was missing a null check so it should be $"\n{e.InnerException?.Message}"); // fails here. It was causing the NullReference error and crashing the CLR.

Thanks for the info. Here are a few clarifications, first of all I do not have access to the C++ source code - it's a third party application which can work with plugin DLLs. I wrote the DLL in C# and exported the functions using DllExport.

I would like to have a blanket approach where if I did not catch a specific error in my code I have a general catch all unhandled exceptions code which would at least log the error or show a message. I tried the following code but it does not seem to work. Could you please advise. Thanks.

[DllExport(CallingConvention = CallingConvention.StdCall)]
public static void TestFunc()
{
	AppDomain.CurrentDomain.UnhandledException +=
		(object sender, UnhandledExceptionEventArgs e)
		=> MessageBox.Show($"UnhandledException");

	Application.ThreadException +=
		(object sender, ThreadExceptionEventArgs e)
		=> MessageBox.Show($"ThreadException: {e?.Exception?.Message}");

	MessageBox.Show("exception incoming");
	throw new Exception();
	// The host kills the DLL thread and the message boxes do not pop up
}

@3F
Copy link
Owner

3F commented Oct 2, 2018

@Olby2000 Try to force route the exceptions via UnhandledExceptionMode.CatchException if you're using System.Windows.Forms.

Also note, MessageBox.Show can cause a deadlocks for different MTA/STA models. Here, I already mentioned about this:

  1. Meta Trader 4 oftenly frozen when launching c# DLL with [DLLExport] #69 (comment)
  2. Meta Trader 4 oftenly frozen when launching c# DLL with [DLLExport] #69 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants