В рамках этого упражнения по ознакомлению с использованием C# DLL в неуправляемом C++ через COM я пытаюсь понять, как работает обработка исключений. Я написал крошечную dll C#, которая просто содержит функцию, которая генерирует исключение, и функцию C++, которая вызывает эту функцию и пытается перехватить исключение.
Вот DLL, написанная на C# с использованием Visual Studio 2012:
namespace ExceptionThrowingLib
{
public interface IExceptionThrower
{
void ThrowException();
}
public class ExceptionThrower : IExceptionThrower
{
public ExceptionThrower() { }
public void ThrowException()
{
using (StreamWriter writer = new StreamWriter("c:/misc/exceptionthrower.txt", true))
{
writer.WriteLine("Exception generation request received at " + DateTime.Now.ToString());
}
throw new Exception("This is a requested exception.");
using (StreamWriter writer = new StreamWriter("c:/misc/exceptionthrower.txt", true))
{
writer.WriteLine("This should never appear in the output file.");
}
}
}
}
А вот функция, которая пытается его использовать, написанная на C++ с использованием Visual Studio 2008:
void HandleException()
{
IExceptionThrowerPtr pThrower(__uuidof(ExceptionThrower));
try
{
pThrower->ThrowException();
AfxMessageBox(_T("No exception caught."));
}
catch (...)
{
AfxMessageBox(_T("I caught an exception!"));
}
}
Когда я вызываю эту функцию, появляется сообщение "Исключение не обнаружено".
Я ожидал, что клиентская (C++) сторона сможет поймать объект _com_error и обработать его соответствующим образом, чтобы узнать, что произошло, но, похоже, ничего не перехватывается. Почему бы нет? Я делаю что-то неправильно?
Спасибо.
Вы на самом деле не делаете ничего плохого, но имеете неправильное понимание.
Код C++ не перехватывает исключение, потому что в код C++ не выдается исключение. Уровень CLR/interop в среде выполнения .NET перехватывает исключение до того, как оно будет передано обратно. Весь хороший код COM никогда не выдает исключение из метода или свойства COM, а возвращает код ошибки.
Каков код возврата (HRESULT) от ThrowException(). Это не должно быть S_OK, но может быть E_FAIL или какая-то другая описательная ошибка.
Я нигде не читал, что он использует _com_ptr_t или какой-либо автоматически сгенерированный код. Он просто говорит о _com_error, который определен в comdef.h, если мне не изменяет память.
Я автоматически сгенерировал код интерфейса, установив для ComVisible значение true в AssemblyInfo.cs, выбрав «Регистрация для Com Interop» в настройках сборки проекта C# и используя #import для полученной библиотеки типов.
Вы использовали #импорт для создания реализации _com_ptr
?
Если это так, позаботьтесь о том, чтобы опустить директиву raw_interfaces_only, так как она подавляет генерацию функций-оболочек для обработки ошибок.
Большое спасибо! Я создал классы C# и C++, слепо следуя директиве эта ссылка, которая не объясняла директиву raw_interfaces_only.
Уровень COM-взаимодействия прозрачно сопоставляет исключения .NET с HRESULTS, которые затем могут быть перехвачены собственными клиентами, как описано здесь. Код OP, по-видимому, использует реализацию автогенерируемая
_com_ptr_t
, которая в своей конфигурации по умолчанию выдает_com_error
, если возвращаемый HRESULT указывает на ошибку.