Прежде всего, если вы хотите предотвратить сбой приложения с помощью приведенного выше кода, вам нужно использовать SetUnhandledExceptionFilter , например:
LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionInfo)
{
// do something useful
return EXCEPTION_EXECUTE_HANDLER; // prevent crash
}
int _tmain(int argc, _TCHAR* argv[])
{
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
...
}
Но это может быть не такчто вы действительно хотите.Одно из решений (как я полагаю, предложено Polity) - создать промежуточный домен AppDomain, который может легко перехватывать все необработанные исключения.Вы можете сделать это в C # следующим образом:
public class PluginVerifier
{
public static int CheckPlugin(string arguments)
{
AppDomain appDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString());
appDomain.UnhandledException += AppDomainUnhandledException;
object obj = appDomain.CreateInstanceAndUnwrap("ExceptionThrower", "ExceptionThrower.MainExceptionThrower");
object ret = obj.GetType().InvokeMember("Startup", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, obj, new object[] { arguments });
AppDomain.Unload(appDomain);
return (int)ret;
}
private static void AppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
AppDomain appDomain = (AppDomain)sender;
// the following will prevent "this should never print" to happen
AppDomain.Unload(appDomain);
}
}
Чтобы это работало, вам нужно сделать два изменения в ваших классах плагинов:
- они должныпроизводный от MarshalByRefObject
- метод плагина не должен быть статическим (вызов статических методов не проходит через фильтр AppDomain)
Таким образом, ваш класс будет записан так:
public class MainExceptionThrower: MarshalByRefObject
{
public int StartUp(string arguments)
{
...
}
}
Если вы сделаете это, вы можете удалить вызовы SetUnhandledExceptionPolicy, SetActionOnFailure или SetDefaultAction и просто заменить загрузочный код следующим образом:
hr = runtimeHost->ExecuteInDefaultAppDomain(L"PluginSystem.dll", L"PluginSystem.PluginVerifier", L"CheckPlugin", L"test", &returnVal);
Если вы попробуете это с вашим кодом запуска выше,этот вызов вернет hr = 0x80131604, что является COR_E_TARGETINVOCATION (TargetInvocationException).