Делает ли Vista более строгую проверку идентификаторов интерфейсов в вызовах DCOM? (заглушка получила плохие данные)? - PullRequest
5 голосов
/ 15 сентября 2008

Я надеюсь, что каждый извинит за длину и повествовательность этого вопроса. Я решил описать ситуацию более подробно в своем блоге. Позже я увидел приглашение Джоэла на этот сайт и решил вставить его сюда, чтобы узнать, есть ли у кого-нибудь понимание ситуации.

Я написал и теперь поддерживаю приложение, состоящее из толстого клиента Visual Basic, говорящего от компонентов DCOM до COM + среднего уровня, написанных на C ++ с использованием ATL. Он работает во всех восьми наших офисах. В каждом офисе размещается внутренний сервер, содержащий приложение COM + (состоящее из 18 отдельных компонентов) и SQLServer. SQLServer обычно находится на том же внутреннем сервере, но не обязательно.

Недавно мы перенесли внутренний сервер в нашем крупнейшем офисе - Нью-Йорке - из кластера MSC на новую виртуальную машину, размещенную на технологии ESW от VMWare. Поскольку местоположение приложения COM + было перенесено со старого сервера на новый с другим именем, мне пришлось перенаправить всех клиентов, чтобы они активировали приложение COM + на новом сервере. Это была старая процедура, поскольку я проделал практически то же самое для нескольких небольших офисов, которые прошли аналогичные обновления инфраструктуры.

Все казалось рутинным, и в понедельник утром весь офис - около 1000 рабочих станций с Windows XP - работал на новом сервере без происшествий. Но потом пришел звонок из моей мобильной группы - там был адвокат, работавший дома с подключением VPN, который получал странную ошибку после перенаправления на новый сервер:

Error on FillTreeView2 - The stub received bad data.

А? Я никогда не видел это сообщение об ошибке раньше. Был ли это новый сервер? Но все рабочие станции в офисе работали нормально. Я сказал мобильной группе переключить адвоката обратно на старый сервер (который все еще работал), и ошибка исчезла. Так в чем же разница? Оказывается, этот адвокат работал с Vista дома.

Мы не работаем с Vista ни в одном из наших офисов, но у нас есть несколько адвокатов, которые работают с Vista дома (конечно, некоторые в моем нью-йоркском офисе). Я делаю так же, и я никогда не видел эту проблему. Чтобы подтвердить, что есть проблема, я запустил свой ноутбук Vista, указал его на новый сервер и получил ту же ошибку. Я указал на старый сервер, и он работал нормально. Ясно, что была проблема с Vista и компонентами на новом сервере - проблема, которая, похоже, не затрагивала клиентов XP. Что бы это могло быть?

Следующая остановка - журнал ошибок приложения на моем ноутбуке. Это дало больше информации об ошибке:

Source:        Microsoft-Windows-RPC-Events
Date:          9/2/2008 11:56:07 AM
Event ID:      10
Level:         Error
Computer:      DevLaptop
Description:   Application has failed to complete a COM call because an incorrect
interface ID was passed as a parameter.

The expected Interface ID was 00000555-0000-0010-8000-00aa006d2ea4, 
The Interface ID returned was 00000556-0000-0010-8000-00aa006d2ea4.

User Action - Contact the application vendor for updated version of the application.

Идентификаторы интерфейса предоставили подсказку, необходимую для разгадки тайны. «Ожидаемый» идентификатор интерфейса идентифицирует интерфейс Recordset MDAC - в частности, версию 2.1 этого интерфейса. «Возвращенный» интерфейс соответствует более поздней версии Recordset (версия 2.5, которая отличается от версии 2.1 включением одной дополнительной записи в конце vtable - метода Save).

Действительно, интерфейсы моего компонента предоставляют множество методов, которые передают Recordset в качестве выходного параметра. Так они вдруг вернули более позднюю версию Recordset - с другим идентификатором интерфейса? Это, конечно, казалось, имело место. И тогда я подумал, почему это должно иметь значение. Vtable выглядит так же для клиентов старого интерфейса. Действительно, я подозреваю, что если бы мы говорили о внутрипроцессном COM, а не о DCOM, это явно безвредное несоответствие импеданса было бы незаметно проигнорировано и не вызвало бы никаких проблем.

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

Почему я возвращал другой интерфейс в параметрах вывода из методов на моем новом сервере?

Почему это коснулось только клиентов Vista?

Поскольку мое серверное программное обеспечение было размещено на серверах в каждом из моих восьми офисов, я решил попробовать нацелить свой клиент Vista на все из них по порядку, чтобы увидеть, у кого были проблемы с Vista, а какие нет. Осветительный тест. Некоторые из старых серверов все еще работали с Vista, но более новые - нет. Хотя некоторые из старых серверов все еще работали под управлением Windows 2000, в то время как новые были в 2003 году, проблема, похоже, не возникала.

После сравнения дат компонентных библиотек DLL выяснилось, что всякий раз, когда клиент указывает на серверы с компонентными библиотеками, выпущенными до 2003 г., Vista работала нормально. Но те, у которых были DLL с датами после 2003 года, были проблематичными. Верьте или нет, в течение многих лет не было (или, по крайней мере, никаких существенных) изменений в коде компонентов сервера. Очевидно, разные даты были просто из-за перекомпиляции моих компонентов на моей машине (ах) разработки. И оказалось, что одна из этих перекомпиляций произошла в 2003 году.

Лампочка зажглась. При передаче наборов записей обратно с сервера на клиент мои компоненты ATL C ++ ссылаются на интерфейс как _Recordset. Этот символ происходит из библиотеки типов, встроенной в msado15.dll. Это строка, которая была у меня в коде C ++:

#import "c:\Program Files\Common Files\System\ADO\msado15.dll" no_namespace rename ( "EOF", "adoEOF" )

Не обманывайтесь 15 в msdad15.dll. Очевидно, эта DLL не изменила имя в длинной серии версий MDAC.

Когда я скомпилировал приложение в тот же день, версия MDAC была 2.1. Итак, _Recordset скомпилирован с идентификатором интерфейса 2.1, и это интерфейс, возвращаемый серверами, на которых работают эти компоненты.

Все клиенты используют прокси приложения COM +, который был сгенерирован (я полагаю) еще в 1999 году. Библиотека типов, определяющая мои интерфейсы, содержит строку:

importlib("msado21.tlb");

, который объясняет, почему они ожидают версию 2.1 набора записей в выходных параметрах моего метода. Очевидно, проблема была в моей перекомпиляции 2003 года и в том факте, что в то время символ _Recordset больше не соответствовал версии 2.1. Действительно _Recordset соответствует версии 2.5 с его отличным идентификатором интерфейса. Решением для меня было изменить все ссылки с _Recordset на Recordset21 в моем коде C ++. Я перестроил компоненты и развернул их на новом сервере. Вуаля - клиенты снова казались счастливыми.

В заключение, у меня остались два ноющих вопроса.

Почему инфраструктура прокси / заглушки работает с клиентами Vista по-разному? Похоже, что Vista делает более строгие проверки идентификаторов интерфейса, возвращающихся из параметров метода, чем XP.

Как я должен был по-другому это кодировать в 1999 году, чтобы этого не случилось? Предполагается, что интерфейсы являются неизменяемыми, и когда я перекомпилировал в более новую версию MDAC, я случайно изменил свой интерфейс, потому что методы теперь возвращали другой интерфейс Recordset в качестве выходного параметра. Насколько я знаю, в библиотеке типов в то время не было символа для конкретной версии, то есть более поздние версии библиотек типов MDAC определяют Recordset21, но этот символ не был доступен в библиотеке типов 2.1.

1 Ответ

2 голосов
/ 18 сентября 2008

Когда Microsoft получила религию безопасности, DCOM (и базовый RPC) получил много внимания, и, безусловно, были внесены изменения, чтобы закрыть дыры в безопасности, которые привели к ужесточению маршалинга. Я удивлен, что вы видите это в Vista, но не в XP, но вполне возможно, что для Vista были добавлены дополнительные проверки. Кроме того, возможно, что необязательная строгость в XP была сделана обязательной в Vista.

Хотя я не знаю достаточно о MDAC, чтобы знать, могли ли бы вы предотвратить это, я знаю, что безопасность - это одна из немногих областей, где Microsoft довольно сильно жертвует обратной совместимостью, поэтому возможно, что вы не смогли бы сделал что-то «лучше» еще в 1999 году.

...