Настоящая засада начинается когда это "действие" некому и некогда пробовать и ляпы 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)
Комментариев нет:
Отправить комментарий