четверг, 3 декабря 2009 г.

Pathological Interfaces I: QueryInterface

WTF?К сожалению, далеко не у всех и не всегда удается сходу придумать хорошую архитектуру и "правильный" API. Часто бывает, что архитектура и API должна пройти несколько итераций и метаморфоз перед тем как лишится недостатков и "устаканится". Но на это нужно время. Хотя бы на то, чтоб кто-то мог опробовать это дизайнерское решение в действии.

Настоящая засада начинается когда это "действие" некому и некогда пробовать и ляпы API просачиваются в стандарты.

Речь идет о ляпе в жизненно важном для COM методе QueryInterface, о способе оповещении, что интерфейс не поддерживается. Казалась бы, что тут может быть проще, либо интерфейс поддерживается, либо — нет. Но грабли нашлись даже в такой простой вещи. Вот что написано в MSDN:
"If the object does not support the interface specified in iid, *ppvObject is set to NULL. ... S_OK if the interface is supported, E_NOINTERFACE if not”
Т.е. согласно спекам, любая "хорошая" имплементация QueryInterface, в случае отсутствия запрашиваемого интерфейса, должна вернуть как код ошибки, так и занулить out-параметр *ppvObject.

Слово "хорошая" не зря выделено. API допускает, и даже провоцирует, на "плохую" реализацию: программист может и не занулить указатель на интерфейс, а вернуть только код ошибки E_NOINTERFACE (действительно, а зачем занулять out-параметр, если я возвращаю ошибку; не доглядел; а разве еще и параметр занулять нужно?). И все из-за того что спецификация обязывает сделать два действия, одно из которых совершенно не нужно. Последствия такой вот работы "не по спецификации" могут быть очень печальными — от AV до утечек памяти (вообще то все зависит только от грамотности кода COM-клиента — занулил ли он указатель перед вызовом, и вызывает ли Release в любом или только успешно случае). На самом деле, количество вариантов развития сюжета может быть на много больше, да и последствия могут проявится не сразу.

......

Вот такой вот получился интерфейс с "защитой от дурака" наоборот...

Мораль: Don’t design stupid APIs that return the same information twice!1


Почитать:
1. Pathological QueryInterfaces
2. The ways people mess up IUnknown::QueryInterface (перевод от GunSmoker - Что люди любят делать не так в IUnknown.QueryInterface)

Комментариев нет: