![]() |
|
|
![]()
|
|
| GoldFinch |
|
||||||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: нет Всего: 26 |
Есть длл, написанная на VС++, экспортирующая методы классов (возможно сами классы).
Заголовочных файлов к этой длл нет. При помощи dumpbin.exe были получены экспорты длл, при помощи lib.exe был получен .lib файл, при помощи undname.exe были получены имена и прототипы методов, при помощи IDA был восстановлен порядок методов в таблицах виртуальных методов (ВМТ) Тестовый код "UObject o; o.AddRef;" показал что метод UObject::AddRef() импортируется корректно и генерирует корректный код вызова
Теперь надо получить адрес этого метода. Допустим надо получить адрес простой импортированной функции. Пишем int foo(){return int(&ExitProcess);} получаем mov eax, [__imp__ExitProcess@4] Для метода, пробуем написать int foo(){return int(&UObject::AddRef);} получаем error C2440: приведение типов: невозможно преобразовать 'unsigned long (__stdcall UObject::* )(void)' в 'int' Не существует контекста, в котором такое преобразование возможно Пишем шаблон для преобразования
код int foo(){return int_cast(&UObject::AddRef);} компилится успешно, однако получаем адрес функции которая вызывает метод через таблицу методов
а хочется совсем не этого, хочется получить реальный адрес этого метода, т.е. [__imp_?AddRef@UObject@@UAGKXZ] как это сделать? Это сообщение отредактировал(а) GoldFinch - 16.5.2009, 20:38 |
||||||
|
|||||||
| Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
А метод случаем не виртуальный? Когда ты просишь адрес виртуального метода, то тебе компилятор подсовывает адрес именно функции-переходника, т.к. предполоагается полиморфный вызов в зависимости от this.
И еще один вопрос: неужели банальный GetProcAddress не поможет (с истинным декорированным именем, конечно)? Если функция импортируется, то GetProcAddress должна возвратить ее, а метод с точки зрения линкера - та же функция... С преобразованием типа тут тоже возможны проблемы, конечно... -------------------- ... |
|||
|
||||
| GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: нет Всего: 26 |
Earnest, метод виртуальный. сделать его невиртуальным невозможно, т.к. не будет соответствовать манглинг.
GetProcAddress я както использовал, но потом от этого отказался вроде изза большего объема кода
проблем с преобразованием типа нет, а вот вызов выглядит не очень красиво Это сообщение отредактировал(а) GoldFinch - 16.5.2009, 22:00 |
|||
|
||||
| Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Я и не предлагала сделать его невиртуальным, просто скзала, как компилятор интерпретирует такие вызовы (и заодно указатели). GetProcAddress - это стандартный метод получения адресов функций, чего тут мудрить. А если
не нравится код, напиши обертку к импортируемым классам (чтобы для клиента выглядело все как у "нормальных"). И не совсем понимаю, каким образом твой первый метод решал эту проблему (некрасивого кода вызова). Кстати, ты ведь вроде говорил, что смог построить lib-файл. Так что тогда мешает подключить билиотеку стандартным оразом? Ну, заголовочный файл напиши руками, ты ведь вроде выяснил сигнатуры... Насколько я понимаю, цель именно такая: использовать библиотеку как если бы у нее были открыт интерфейсы (т.е. lib + h)? -------------------- ... |
|||
|
||||
| GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: нет Всего: 26 |
Earnest,
я уже писал в 1м посте, что вызовы методов работают нормально, obj->met(), мне же надо получить адрес метода, не для того чтобы его вызвать, а для последующей работы с этим адресом. |
|||
|
||||
| Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Наверное, пропустила.
В общем, адрес метода - это совсем не адрес с точки зрения компилятора и языка, так что просто &CMyObj::Method будет возвращать адрес стаба, как у тебя и получается. А вот GetProcAddress про C++ и прочий полиморфизм не в курсе, должна выдавать ровно то, что просят. Насчет длинного и некрасивого кода - как писал кто-то из гуру, любую проблему в программировании можно решить с помощью правильно спроектированных прокладок. А на C++ они к тому же почти бесплатны в смысле издержек. -------------------- ... |
|||
|
||||
| GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: нет Всего: 26 |
Earnest, даже если забыть об издержках работы программы, появляются издержки при ее разработке: для того чтобы найти декорированное имя метода для GetProcAddress надо свернуть с MSVC и искать его в таблице экспорта длл, что несколько неудобно.
Если же задуматься об издержках на импорт, то получается что при статическом импорте компилятор удаляет все неиспользуемые импорты и они импортируются поиском в таблице экспорта длл при загрузке программы. При вызове метода через указатель на объект (obj->met) адрес метода берется из ВМТ. При динамическом импорте через GetProcAddress импортирование происходит поиском в таблице экспорта длл в момент вызова GetProcAddres. Будут ли удалены лишние вызовы GetProcAddress - неизвестно. При вызове метода адрес метода берется из переменной с адресом. Однако у меня конкретная длл, которая не будет меняться за все время использования моей программы. Поэтому для импорта можно забить готовые адреса методов сразу на этапе компиляции, они не изменятся. При этом получится наибольшая скорость вызова функций, хотя не очень понятно как это будет выглядеть в коде, и как генерировать этот код из длл. |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 1 Всего: 250 |
а такой тестовый код, что дает ? |
|||
|
||||
| GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: нет Всего: 26 |
mes, вызов через ВМТ
|
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 1 Всего: 250 |
тогда то, что Вы получили в первом примере, относится к оптимизации и получено вследствие того, что компилятору известен реальный тип объекта в компил-тайм. И задача (без знания реального имени функции-реализации), имхо, не выполнима |
|||
|
||||
| GoldFinch |
|
||||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: нет Всего: 26 |
ап!
попробовал написать обертку
есть какие-нибудь идеи как сделать это короче? Это сообщение отредактировал(а) GoldFinch - 19.6.2009, 21:18 |
||||
|
|||||
| Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
GoldFinch, а зачем? Ты код буста видел? Цель в том, чтобы был короче-яснее клиентский код, а обслуживающий... ну, по возможности.
Насчет сократить, я бы попробовала так (имея в виду, что методов сильно не 3). Во-первых, таблица вместо перечисления методов, причем не только имя, но и закодированная сигнатура. Во-вторых, набор типизированных шаблонов для вызова методов по сигнатуре. Шаблоны нужно делать по числу аргументов: для 0, 1, 2, 3 и сколько там по максимуму. Методы имлементировать придется явно, как у и у тебя, но через шаблоны. И еще не поняла, зачем тебе в обертке имитировать тело настоящего класса, все эти VMT, члены-данные... Т.е. если ты можешь правильно установить VMT, но нафига вообще огород городить - напиши объявление класса с правильно расположенными виртуальными функциями. -------------------- ... |
|||
|
||||
| GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: нет Всего: 26 |
Earnest, обертка чтобы спрятать указатели на методы, и она превращает виртуальные методы в длл в невиртуальные, это позволяет вызывать их не зная их порядок в ВМТ (хотя они в оригинале виртуальные, полиморфизм там вроде не используется)
количество методов в 1 классе - до сотен (200-300), классы и длл писал не я код буста не видел, но мне надо будет скорее всего писать все это руками, по мере необходимости добавляя новые методы |
|||
|
||||
| mes |
|
||||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 1 Всего: 250 |
с певого взгляда бросилось в глаза
Зачем сразу ограничивать себя, принуждая дата-члены класса делать статическими. Этот момент интуитивно напрашивается в таком исполнении :
1. Выполнил как функцию, так как таблица принадлежит только этому классу, но если не подходит можно вернуть к "классическому" виду инициализации таблица произойдет при первом вызове функции PtrTable. Если нужно ручное управление инициализацией, то можно добавить функцию: static void Init () { PtrTable(); } или поместить пустой вызов PtrTable() в конструктор в зависимости от требований. ну а красиво скрыть это : (this->*table().Met1) я уверен Вы справитесь сами |
||||||
|
|||||||
| GoldFinch |
|
||||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: нет Всего: 26 |
ап!
почитал про static, действительно оно обладает замечательным свойством инициализировать переменные только 1 раз получается что отдельный класс PtrTable и "static PtrTable& table() { static PtrTable table; return table; }" можно заменить на статическую переменную с адесом метода прямо внутри обертки метода при этом эту переменную можно сделать классом, в конструкторе которого и импортировать метод
получается что вся информация о методе сосредоточена в одном месте, и ее можно завернуть в компактный макрос |
||||
|
|||||
![]()
|
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Visual C++/MFC/WTL | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |