Как получить HRESULT вместо исключения из COM-метода

Я использую метод 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 08.04.2024 15:30

@Good Night Nerd Pride DirectShow устарел. Сейчас его заменяет Медиа Фонд. Но DirectShow продолжает работать.

ffvideoner 08.04.2024 16:45
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
73
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

«Зачем выбрасывать исключение вместо возврата ошибки?»

Это связано с тем, что использование исключений является распространенным методом обработки ошибок в среде .NET.

«Как это исправить?»

Класс COMException содержит свойство HResult со значением HRESULT.

Поэтому вам следует перехватить исключение, как обычно в .NET, а затем использовать это свойство для определения характера ошибки, как указано в документации COM.

Да, я знаю о HRESULT внутри COMException. Но цель состоит в том, чтобы не произошло никаких исключений.

ffvideoner 08.04.2024 16:52

@ffvideoner да, но почему? Как писали я и Charlieface, исключения — это идиоматический способ обработки таких ошибок в .NET, и поэтому я думаю, что извлечение HRESULT из исключения — это правильный путь. Если у вас есть веская причина избегать этого, я думаю, вам следует добавить эту информацию в свой вопрос.

wohlstad 08.04.2024 16:55

Потому что в моем случае одна из ошибок не критична.

ffvideoner 08.04.2024 16:57

Вы все равно можете продолжить выполнение, если HRESULT в вашем случае не критичен. Вам следует просто перехватить исключение, просмотреть HRESULT и выполнить соответствующее разветвление. Конечно, это ваше дело, но я бы не советовал писать неидиоматически, если у вас нет веской причины.

wohlstad 08.04.2024 16:59

Мне удобнее, если Visual Studio показывает COM-исключения, кроме одной ошибки в одном месте. Возможно, это плохой стиль.

ffvideoner 08.04.2024 17:12

Я не голосовал против. Я только проголосовал за правильный ответ. В вопросе я объяснил, что знаю о значении HRESULT.

ffvideoner 08.04.2024 17:20

@ffvideoner мне не было ясно, знаете ли вы, как его извлечь, и в любом случае я считаю, что хорошие ответы на StackOverflow также должны направлять разработчиков к написанию кода в соответствии с передовыми практиками (а не только отвечать на насущные вопросы).

wohlstad 08.04.2024 17:23

Я ничего не имею против этого.

ffvideoner 08.04.2024 17:27
Ответ принят как подходящий

Просто используйте атрибут 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);
}

В моем случае одна из ошибок не критична.

ffvideoner 08.04.2024 16:55

Для этого и нужен try catch. Если код не критичен к производительности, его следует писать как можно более понятным образом.

Charlieface 08.04.2024 17:14

Exception+try+catch — хороший выбор с точки зрения ООП-проектирования, но он требует больших затрат (при повышении) с точки зрения циклов процессора. Во многих случаях при использовании COM требуется просто проверить код ошибки, поскольку это намного проще. Также без PreserveSig вы не сможете легко проверить значения успеха (S_FALSE и другие).

Simon Mourier 08.04.2024 18:24

@SimonMourier Для одного звонка, о котором не стоит думать. Я сказал «если только код не критичен к производительности». Да, если это выполняется в тяжелом цикле или вы знаете, что один из кодов не является исключением, возможно, имеет смысл использовать PreserveSig.

Charlieface 08.04.2024 18:31

Другие вопросы по теме