ger_kar писал(а):А по моему вот нихрена не очевидно. Ну зачем вообще было делать реализациию в vba6.dll и глушить тоже самый, по сути уже реализованный функционал в msvbvm60.dll. Смысла в этом нет никакого.
IDE не использует msvbvm60.dll никак. Ибо в этом нет смысла. vba6.dll и msvbvm60.dll — они скомпилированы из одного и того же кода, но с разными ключами условной компиляции (#if...#endif). И по-разному слинкованы. Всё. В рантайме боевые, облегчённые и отуплённые варианты функций. В vba6 — полные, нацеленные на использования при отладке проектов. Тот же обработчик ошибок в рантайме завершает проект, а под IDE — выдаёт диалог с Continue/End кнопками. Именно из-за этой разницы мой
кирпич для вызова по указателям имеет две почти не пересекающихся ветки в коде.
ger_kay писал(а):И как спрашивается это понимать, если есть этот конкретно взятый интерфейс, то и все соответствующие методы ему присущие тоже должны быть, а иначе тогда это должен быть другой интерфейс.
Я не понимаю. Вернее, похоже ты до сих пор не понимаешь. Судя по этому тексту, ты думаешь, что нужного тебе метода там нет вообще? Нет реализации? Нет ячейки в VTable? И VB не найдя ячейку в VTable жалуется? И недоумеваешь, как же, мол, так: интерфейс тот же, а набор методов отличается?
Да есть там метод. Есть ячейка в VTable, и реализация есть... примерно такая:
- Код: Выделить всё
HRESULT CVbClassTypeInfo::GetTypeAttr(TYPEATTR** ppTypeAttr)
{
return E_NOTIMPL;
}
А вот уже VB получив HRESULT с кодом E_NOTIMPL (not implemented) возвращает ту красноречивую ошибку, что ты видишь.
Vi писал(а):ИМХО, реализация методов интерфейса ITypeInfo живёт в oleaut32.dll и поддерживаются системой, даже если VB нет на машине и в помине. Что-то в ваших рассуждениях непонятно.
Нет, интерфейс — он на то и интерфейс, что может существовать десяток разных классов, его поддерживающих, имеющих разные реализации.
Убедиться в том, что я прав — легко. Достаточно посмотреть потроха интерфейса и VTable под отладчиком.
При работе под IDE:
- vb_itypeinfo_impl_rev_eng_vba.png (47.86 Кб) Просмотров: 9721
Хорошо видно: интерфейс живёт в куче, VTable для интерфейса — в секции данных VBA6.DLL, реализации методов — в секции кода VBA6.DLL
То же самое, но запускаю скомпилированный вариант:
- vb_itypeinfo_impl_rev_eng_vbrt.png (39.13 Кб) Просмотров: 9721
Здесь у меня уже есть отладочные символы для рантайма, так что наглядность существенно увеличивается.
Итак: сам интерфейс живёт в секции данных (ахтунг!
ger_kar, это как раз тот случай, о котором я тебе когда-то говорил) нашего EXE-файла, VTable для интерфейса — внутри рантайма, реализации методов интерфейса — внутри рантайма.
Но если приглядеться, то в VTable вместо некоторых методов стоят какие-то не те имена. Что это, битые символы? На самом деле — нет.
Если мы посмотрим на объявление
ITypeInfo, то увидим, что он унаследован от
IUnknown и первым же методом идёт как раз проблемный
GetTypeAttr:
- vb_itypeinfo_impl_rev_eng_methods_order.png (8.97 Кб) Просмотров: 9721
Теперь сравним вывод OleView и ту vtbl, которую мы видим под отладчиком:
- vb_itypeinfo_impl_rev_eng_vbrt_strange_entries.png (51.7 Кб) Просмотров: 9721
Итак, вместо ожидаемого
CEcTypeInfo::GetTypeAttr мы видим
CTL::EnumConnectionPoints. Что это? Баг? Битые отладочные символы?
На самом неделе — нет, всё нормально, ни багов, ни битых символов. Это просто результат оптимизации, проделанной сишным компилятором при компиляции рантайма в недрах MS. Компиляция проходилась без отладочных опций, поэтому компилятор взял пачку дублирующихся процедур с абсолютно идентичным телом, но разными именами, и заменил их все на одну единственную. Соответственно, имя она получила, видимо, то, которое шло последним по алфавиту из списка дубликатов.
Пойдём и посмотрим, какая же там реализация?
- vb_itypeinfo_impl_rev_eng_gettypeattr_impl.png (1.79 Кб) Просмотров: 9721
Не нужно быть экспертом, чтобы понять, что реализация предельно простая: она просто возвращает HRESULT с кодом 0x80004001, а сама процедура принимает два параметра (this и ещё один).
Я думаю, все уже догадались, что 0x80004001 это и есть E_NOTIMPL, а я наверху правильно предугадал реализацию метода GetTypeAttr.
Таки да, и
CEcTypeInfo::GetTypeAttr, и
CTL::EnumConnectionPoints имели эквивалентный код:
- Код: Выделить всё
HRESULT _stdcall CEcTypeInfo::GetTypeAttr(TYPEATTR** ppTypeAttr)
{
return E_NOTIMPL;
}
- Код: Выделить всё
HRESULT _stdcall CTL::EnumConnections(IEnumConnections** ppenum)
{
return E_NOTIMPL;
}
поэтому компилятор слил их все в одно целое.
Все остальные методы, которые там выше видно, и которые выбиваюттся их темы (типа Scroll) — это тоже заглушки с E_NOTIMPL, которые использовались в чёрт знает скольки местах, и компилятор их все сгруппировал по принципу (принимает N-аргументов, возвращает E_NOTIMPL).
Конечно же, я не делал всех этих исследований при изначальном ответе, но моё представление о сути вещей были в абсолютной точности таким, каким оно оказалось. Так что да, Хакер оказался как всегда прав
Ну и кстати, насчёт того, что реализация ITypeInfo должна жить в oleaut32.dll. Оно так и есть, если ссылка на интерфейс получена от
LoadTypeLib,
LoadTypeLib,
CreateTypeLib,
CreateTypeLibEx, которые в этой библиотеке живут.