Почему возвращаемый тип AddRef() и Release() НЕ HRESULT

Недавно начали изучать COM. В COM возвращаемый тип функций должен быть HRESULT. Читал про HRESULT, проблемы с GetLastError(), но тогда почему функции IUnknown, AddRef() и Release() имеют тип возврата ULONG?

Я пришел к выводу, что AddRef() (почти) всегда вызывается из QueryInterface(), и клиент не должен его вызывать. А для Release() его возвращаемое значение никогда не проверяется.

Хотя я могу поспорить со своими ответами - для AddRef() - у клиента может быть ситуация, что он должен позвонить. И поскольку у клиента есть доступ к этой функции, какова гарантия, что клиент не вызовет ее.

для Release() - Опять же, пользователь может проверить тип возвращаемого значения, потому что он МОЖЕТ

Просьба уточнить.

Кроме того, это похоже на --> Его соглашение состоит в том, чтобы иметь тип возвращаемого значения HRESULT для функций, связанных с COM, а не принуждение --> Если это правда, это остановит путаницу в моем мозгу.


person user2705939    schedule 22.01.2014    source источник
comment
AddRef и Release не могут выйти из строя, поэтому нет смысла заставлять их возвращать HRESULT. Что касается вашего последнего вопроса: методы [local] не должны вернуть HRESULT (хотя могут, если захотят); все остальные методы должны возвращать HRESULT. Это связано с тем, что уровень маршалинга должен иметь возможность сообщать о своих собственных ошибках (например, о сбое сети, если вызов выходит за пределы машины, а удаленный хост недоступен). AddRef и Release это [local]   -  person Igor Tandetnik    schedule 22.01.2014
comment
Без необходимости в статусе успеха/неудачи (см. Игоря выше), возвращаемое значение повторно используется для чего-то полезного, что является указанием счетчика ссылок. Это делает эти очень часто используемые методы легкими и эффективными.   -  person Roman R.    schedule 22.01.2014
comment
@IgorTandetnik Спасибо за ответ. Тем не менее, я все еще думаю, что клиенту может понадобиться позвонить AddRef(). Например, предположим, что у клиента есть указатель локального интерфейса, который будет назначен действительным указателем интерфейса, возвращаемым сервером. А если и клиент, и сервер — это два разных процесса, их адресные пространства тоже будут разными. Таким образом, если pIOne отправляется сервером, а pIOneTemp является локальным, то после оператора pIOneTemp = pIOne; клиенту придется вызывать AddRef() на pIOneTemp просто потому, что он находится в совершенно другом адресном пространстве. Теперь, почему он не должен возвращать HRESULT?   -  person user2705939    schedule 23.01.2014
comment
@РоманР. Но тогда почему это не нарушение единообразия? Если COM запрашивает написанные нами методы с типом возвращаемого значения HRESULT, только его собственные методы IUnknown не следуют правилу. Также см. мой комментарий выше, и, пожалуйста, объясните, что если возникнет такой случай?   -  person user2705939    schedule 23.01.2014
comment
Я никогда не утверждал, что клиенту никогда не нужно вызывать AddRef. Как вы думаете, какую часть моего комментария можно истолковать таким образом? Если бы клиенту никогда не приходилось вызывать AddRef, то интерфейс IUnknown изначально не предоставлял бы AddRef. Но какое отношение все это имеет к возвращению HRESULT? Есть ли в книгах закон о том, что любой метод, который можно вызвать, должен возвращать HRESULT?   -  person Igor Tandetnik    schedule 23.01.2014
comment
Вы говорите о нарушении единообразия, как о нарушении контракта. Кто-то обещал вам единообразие (какое бы оно ни было), а потом нарушил свое обещание? В какой части документации указано, что COM-интерфейс должен обеспечивать единообразие?   -  person Igor Tandetnik    schedule 23.01.2014
comment
У вас не может быть указателя, который содержит адрес в адресном пространстве другого процесса. Ваш указатель pOne на самом деле является указателем на прокси, созданный уровнем маршалинга COM и находящийся в вашем процессе. pOne->AddRef() вызывает AddRef на этом прокси - этот вызов никогда не направляется на удаленный сервер. Как я уже сказал, AddRef и Release являются [local] методами. Дополнительные сведения см. в разделе msdn.microsoft.com/en-us. /библиотека/окна/рабочий стол/ms693719.aspx   -  person Igor Tandetnik    schedule 23.01.2014
comment
COM требует, чтобы написанные нами методы возвращали тип HRESULT Не всегда обязательно. его собственные методы IUnknown только не следуют правилу Неверно, есть и другие.   -  person Roman R.    schedule 23.01.2014
comment
почти уверен, что это просто незначительное раздражение/снижение производительности для отражения (для сопоставления информации о типе с объектами разных языков и обратно), поскольку в библиотеках типов есть информация, необходимая для решения, является ли возвращаемый тип HRESULT, возвращает ли он HRESULT через аргумент, или если он никогда не терпит неудачу.   -  person Dmitry    schedule 19.03.2018


Ответы (2)


«AddRef и Release никогда не могут дать сбой, поэтому нет смысла заставлять их возвращать HRESULT». -Игорь Тандетник

Я публикую это как ответ только потому, что мои глаза кровоточат от чтения всего этого вопроса и всех комментариев в надежде помочь кому-то ... давай, сообщество SO, давайте закроем такие вопросы. Было бы гораздо проще помочь людям без всего этого барахла просеивать.

person eselk    schedule 27.08.2014

Задаюсь похожим вопросом: зачем нам 3 метода в интерфейсе вместо 2-х? QueryInterface и Release должно быть достаточно. QI уже выполняет AddRef, и теоретически, если у нас есть 2 метода, используемых для выполнения практически одной и той же работы, один из них следует исключить. QI делает свое дело плюс AddRef. AddRef делает только AddRef. АддРеф умирает. ЦЕЛОВАТЬ.

Теперь, что касается возвращаемого типа, я не согласен с комментарием о том, что AddRef/Release никогда не может дать сбой. Что ж, они могут. По-разному, и они должны следовать одному и тому же правилу возврата HRESULT и результатов в параметрах.

Один из способов, с помощью которого AddRef может потерпеть неудачу, заключается в том, что вы можете превысить ULONG_MAX (трудно достижимо, но возможно). Или семафор, который используется для обеспечения потокобезопасности этого вызова, может вызвать исключение. На самом деле так много вещей может пойти не так, что единственная причина, по которой я могу представить, что в спецификации это было просто ULONG(void), - это производительность, поскольку гораздо проще вызывать метод без параметров.

Производительность клиента была вещью еще в 90-х годах, сейчас она определенно не имеет значения (если вы не говорите об ограниченном клиенте, таком как мобильное устройство). Пожертвовав семантикой во имя производительности, COM-дизайн фактически создал долгосрочную нагрузку на техническое обслуживание за счет краткосрочного выигрыша в производительности, о котором все знали и знают, что он всегда уходит (закон Мура, емкость удваивается каждые 18 секунд). месяцев по той же цене).

Но даже в этом случае AddRef не следует вызывать так часто. Это означает, что вы носите один и тот же объект по нескольким частям вашей системы, что само по себе является явным признаком плохого дизайна.

Я также не согласен с тем, что это плохой вопрос. Это хороший вопрос, потому что он заставляет людей задуматься. SO — это ответы на конкретные вопросы, потому что люди застревают. Тем не менее, заставляя людей думать над широкими/открытыми вопросами, вы обучаете их навыкам, которые в первую очередь предотвратят их застревание.

person See Sharper    schedule 12.04.2018