Реализация ISupportErrorInfo - что это значит?

Что означает интерфейс ISupportErrorInfo? Я немного потерял, чтобы понять это. Из MSDN:

Этот интерфейс гарантирует, что ошибка информация может правильно позвонить. автоматизация объекты, использующие обработку ошибок интерфейсы должны реализовывать ISupportErrorInfo.

Этот метод указывает, действительно ли интерфейс поддерживает IErrorInfo интерфейс.

HRESULT InterfaceSupportsErrorInfo(
  REFIID riid
);

Что означает возврат S_OK в InterfaceSupportsErrorInfo? Если вы вернете S_OK для всех интерфейсов? Просто некоторые?

Ответ 1

Мое понимание этого (на основе некоторых связанных страниц MSDN) заключается в том, что, реализуя ISupportErrorInfo, вы указываете, что один или несколько интерфейсов в вашем классе возвращают информацию об ошибках, вызывая SetErrorInfo, а не просто возвращая отказ HRESULT.

Для этого ваша реализация ISuportErrorInfo::InterfaceSupportsErrorInfo должна возвращать S_OK только для тех интерфейсов в вашем классе, которые фактически используют SetErrorInfo, чтобы возвращать информацию об ошибке вызывающему, и только эти интерфейсы.

Например, скажем, у вас есть класс, который реализует интерфейс, который вы написали, называется IFoo, который имеет метод DoSomething. Если кто-то другой создает экземпляр вашего класса и вызывает IFoo::DoSomething, они должны делать следующее, если DoSomething возвращает сбой HRESULT (перефразируя с разных страниц MSDN, но я начал здесь: http://msdn.microsoft.com/en-us/library/ms221510.aspx):

  • Вызвать QueryInterface указателем IFoo для получения интерфейса ISupportErrorInfo для объекта, который реализует IFoo

  • Если вызываемый объект не реализует ISupportErrorInfo, то вызывающий для обработки ошибки на основе HRESULT или передать его стек вызовов.

  • Если вызываемый объект реализует ISupportErrorInfo, то вызывающий должен вызвать ISupportErrorInfo::InterfaceSupportsErrorInfo, передав в REFIID для интерфейса, который возвратил ошибку. В этом случае метод DoSomething интерфейса IFoo возвратил ошибку, поэтому вы передали бы REFIID_IFoo (при условии, что он определен) на InterfaceSupportsErrorInfo.

  • Если InterfaceSupportsErrorInfo возвращает S_OK, затем вызывающий на данный момент знает, что он может получить более подробную информацию об ошибке, вызвав GetErrorInfo. Если InterfaceSupportsErrorInfo возвращает S_FALSE, вызывающий может предположить, что вызываемый интерфейс не предоставляет подробную информацию об ошибке, и ему придется полагаться на возвращенный HRESULT, чтобы выяснить, что произошло.

Причина этого несколько запутывающего/запутанного API обработки ошибок представляется для гибкости (насколько я могу сказать в любом случае. Это COM все-таки;). С помощью этой конструкции класс может поддерживать несколько интерфейсов, но не каждый интерфейс должен использовать SetErrorInfo для возврата информации об ошибках из своих методов. Вы можете иметь определенные, выбирать интерфейсы в своем классе, возвращать подробную информацию об ошибке через SetErrorInfo, в то время как другие интерфейсы могут продолжать использовать обычный HRESULT для указания ошибок.

Таким образом, интерфейс ISupportErrorInfo является способом информирования вызывающего кода, что хотя бы один из интерфейсов, реализуемых вашим классом, может возвращать подробную информацию об ошибках, а метод InterfaceSupportsErrorInfo сообщает вызывающему абоненту, является ли данный интерфейс одним этих интерфейсов. Если это так, то вызывающий абонент может получить подробную информацию об ошибке, вызвав GetErrorInfo.