Я использую метод IAMCameraControl.GetRange на C#. В описании ничего не сказано об исключениях. Только о возврате значения ошибки HRESULT
. Но в моем коде встречается COMException
, внутри которого указан HRESULT
.
Зачем создавать исключение вместо возврата ошибки? Как это исправить?
[ComVisible(true)]
[ComImport]
[Guid("C6E13370-30AC-11d0-A18C-00A0C9118956")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAMCameraControl
{
int GetRange([In] CameraControlProperty property, [In][Out] ref int pMin, [In][Out] ref int pMax, [In][Out] ref int pSteppingDelta, [In][Out] ref int pDefault, [In][Out] ref int pCapsFlag);
int Set([In] CameraControlProperty property, [In] int lValue, [In] int flags);
int Get([In] CameraControlProperty property, [In][Out] ref int lValue, [In][Out] ref int flags);
}
@Good Night Nerd Pride DirectShow устарел. Сейчас его заменяет Медиа Фонд. Но DirectShow продолжает работать.
«Зачем выбрасывать исключение вместо возврата ошибки?»
Это связано с тем, что использование исключений является распространенным методом обработки ошибок в среде .NET.
«Как это исправить?»
Класс COMException содержит свойство HResult со значением HRESULT
.
Поэтому вам следует перехватить исключение, как обычно в .NET, а затем использовать это свойство для определения характера ошибки, как указано в документации COM.
Да, я знаю о HRESULT внутри COMException. Но цель состоит в том, чтобы не произошло никаких исключений.
@ffvideoner да, но почему? Как писали я и Charlieface, исключения — это идиоматический способ обработки таких ошибок в .NET, и поэтому я думаю, что извлечение HRESULT из исключения — это правильный путь. Если у вас есть веская причина избегать этого, я думаю, вам следует добавить эту информацию в свой вопрос.
Потому что в моем случае одна из ошибок не критична.
Вы все равно можете продолжить выполнение, если HRESULT в вашем случае не критичен. Вам следует просто перехватить исключение, просмотреть HRESULT и выполнить соответствующее разветвление. Конечно, это ваше дело, но я бы не советовал писать неидиоматически, если у вас нет веской причины.
Мне удобнее, если Visual Studio показывает COM-исключения, кроме одной ошибки в одном месте. Возможно, это плохой стиль.
Я не голосовал против. Я только проголосовал за правильный ответ. В вопросе я объяснил, что знаю о значении HRESULT.
@ffvideoner мне не было ясно, знаете ли вы, как его извлечь, и в любом случае я считаю, что хорошие ответы на StackOverflow также должны направлять разработчиков к написанию кода в соответствии с передовыми практиками (а не только отвечать на насущные вопросы).
Я ничего не имею против этого.
Просто используйте атрибут PreserveSig.
[ComImport, Guid("c6e13370-30ac-11d0-a18c-00a0c9118956"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAMCameraControl
{
[PreserveSig]
int GetRange(...)
...
}
Правильный способ обработки HResult
— создать исключение, поскольку это «исключительный» результат. В .NET предусмотрена специальная обработка HResult
, позволяющая преобразовать HResult
в исключение, что в .NET более идиоматично.
Вы могли бы использовать [PreserveSig]
, чтобы подавить эту обработку, но я не уверен, зачем вам это нужно.
Поэтому удалите возвращаемое значение int
. Также не следует указывать [ComVisible]
, а значения [in][Out] ref
должны быть [Out] out
.
[ComImport]
[Guid("C6E13370-30AC-11d0-A18C-00A0C9118956")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAMCameraControl
{
void GetRange([In] CameraControlProperty property, [Out] out int pMin, [Out] out int pMax, [Out] out int pSteppingDelta, [Out] out int pDefault, [Out] out int pCapsFlag);
void Set([In] CameraControlProperty property, [In] int lValue, [In] int flags);
void Get([In] CameraControlProperty property, [Out] out int lValue, [Out] out int flags);
}
В моем случае одна из ошибок не критична.
Для этого и нужен try catch
. Если код не критичен к производительности, его следует писать как можно более понятным образом.
Exception+try+catch — хороший выбор с точки зрения ООП-проектирования, но он требует больших затрат (при повышении) с точки зрения циклов процессора. Во многих случаях при использовании COM требуется просто проверить код ошибки, поскольку это намного проще. Также без PreserveSig вы не сможете легко проверить значения успеха (S_FALSE и другие).
@SimonMourier Для одного звонка, о котором не стоит думать. Я сказал «если только код не критичен к производительности». Да, если это выполняется в тяжелом цикле или вы знаете, что один из кодов не является исключением, возможно, имеет смысл использовать PreserveSig
.
В документации говорится, что вы используете устаревшую функцию. Может быть, документация просто устарела? Может быть, базовая реализация изменилась? Или, может быть, это транзитивная зависимость, которая изменилась и теперь выдает исключения?