Что вы можете сделать, это использовать Concord , механизм отладки, который поставляется с Visual Studio (начиная с версии 2012). Он достаточно расширяемый через красивый управляемый API (и может быть развернут с использованием технологии vsix), но он не полностью документирован.
В Concord есть концепция отладочных мониторов, которую мы можем подключить, используя IDkmDebugMonitorExceptionNotification Interface
Самое классное, что этот интерфейс может отслеживать все исключения брошенные. Он также может «подавлять» любое обнаруженное исключительное событие, и это именно то, что нам нужно.
Я предлагаю начать с образца Hello World :. Загрузите его и убедитесь, что он работает так, как ожидалось.
Теперь просто измените HelloWorld.vsdconfigxml
следующим образом:
<!--TODO: If you copy the sample, ensure to regenerate the GUID in this file -->
<!-- 1. change component level to something higher than 40500 -->
<ManagedComponent
ComponentId="51736b11-9fb4-4b6d-8aca-a10a2b7ae768"
ComponentLevel="40501"
AssemblyName="HelloWorld">
<!-- 2. change class full name to HelloWorld.ExceptionHandler, for example -->
<Class Name="HelloWorld.ExceptionHandler">
<Implements>
<InterfaceGroup>
<NoFilter/>
<!-- 3. change supported interface -->
<Interface Name="IDkmDebugMonitorExceptionNotification"/>
</InterfaceGroup>
</Implements>
</Class>
</ManagedComponent>
Затем просто создайте класс ExceptionHandler.cs
и поместите в него что-то вроде этого:
public class ExceptionHandler : IDkmDebugMonitorExceptionNotification
{
private bool _unhandledDetected;
// we're being called!
public void OnDebugMonitorException(DkmExceptionInformation exception, DkmWorkList workList, DkmEventDescriptorS eventDescriptor)
{
if (_unhandledDetected)
{
// this will cause the program to terminate
eventDescriptor.Suppress();
return;
}
if (exception.ProcessingStage.HasFlag(DkmExceptionProcessingStage.Unhandled))
{
_unhandledDetected = true;
}
else if (exception.ProcessingStage.HasFlag(DkmExceptionProcessingStage.Thrown))
{
if (SuppressException(exception))
{
eventDescriptor.Suppress();
}
}
}
// should we suppress a thrown (1st chance) exception?
private bool SuppressException(DkmExceptionInformation exception)
{
// implement any custom logic in here, for example use the exception's name
if (exception.Name == typeof(ArgumentOutOfRangeException).FullName)
{
// for example, use the module (assembly) name
var clrAddress = (DkmClrInstructionAddress)exception.InstructionAddress;
var clrModule = clrAddress.ModuleInstance;
if (clrModule.Name == "TheUglyOne.dll")
return true; // we don't want this one!
}
return false;
}
}
Когда вы запускаете проект, вы должны видеть, как отслеживаются все исключений (независимо от настроек «только мой код» и / или триггеров исключений), так что вам просто нужно реализовать некоторую логику чтобы подавить тех, кого вы действительно не хотите видеть. Я не проверял, но я полагаю, что вы могли бы построить свою логику, используя пользовательские атрибуты, так как классы Dkm предоставляют довольно много информации метаданных .NET.
Примечание: как вы можете видеть, есть некоторая хитрость, чтобы гарантировать нормальное завершение программы.