Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.216.233.58] |
|
Сообщ.
#1
,
|
|
|
Всем привет!
В общем есть функция, перегруженная: extern "C" __declspec(dllexport) UINT __stdcall Foo( MSIHANDLE handle ) extern "C" __declspec(dllexport) UINT __stdcall Foo( MSIHANDLE handle, DWORD rid ) Плюс ко всему она объявлена в *.def файле: LIBRARY "SomeLibrary" EXPORTS Foo Естественно такой код генерирует варнинг что типа много раз пометили функцию как экспортируемую, уберите ее из def файла или уберите модификатор dllexport. Убрал модификаторы экспорта, получил: UINT __stdcall Foo( MSIHANDLE handle ) UINT __stdcall Foo( MSIHANDLE handle, DWORD rid ) После чего летит ошибка: 1>SomeFile.def : warning LNK4022: cannot find unique match for symbol 'Foo' Почитал всякое, советуют убрать экспорт из *.def файла, и оставить extern "C" __declspec(dllexport) - но это не вариант! Потому как без def файла для x86 архитектуры функции экспортируются с декорированными именами, из за чего InstallShield их просто не видит. Почитал еще, предлагают в *.def файл запихнуть собственно две версии этой функции с перегрузкой, что то типа: LIBRARY "SomeLibrary" EXPORTS ?Foo@@YAIK@Z ?Foo@@YAIKK@Z Ну я так собственно и попробовал сделать. Все скомпилилось удачно, без варнингов, но для x64 конфигурации, для win32 - говорит что линкер не может найти эти функции. Теперь вопрос - как с помощью def файла экспортировать эти две функции? Возможно ли такое? Добавлено Да еще забыл сказать, перегруженная версия Foo с двумя параметрами, вызывается внутри Foo с одним параметром. И на сколько я понял - по сути экспортировать нужно одну версию: UINT __stdcall Foo( MSIHANDLE handle ) Конечно можно поменять имя второй функции. Но мне просто интересно стало - как без изменения имени экспортировать. Добавлено Так же что то начал тут экспериментировать. Еслиэти две функции заинлайнить, то ошибка пропадает. Может ли быть это ответом на мой вопрос? Добавлено Хм! Если экспортировать эти две функции, но при этом заинлайнить их, ошибки нет, в таблице экспорта: 19 12 000085A0 Foo Правильно ли я понимаю, что теперь при использовании будет использоваться та версия экспортируемой функции - которая была вызвана? Нет тут скрытых камней? |
Сообщ.
#2
,
|
|
|
В общем похоже с инлайн фигня получается. Похоже придется менять имя второй функции.
|
Сообщ.
#3
,
|
|
|
KILLER, для перегруженных сущностей нужна декорация имён. Без вариантов. Если они при этом импортируются, то и в таблицах экспорта они должны проходить в декорированном виде.
Как вариант, ты можешь заинлайнить – без их экспорта/импорта – простые переходники, которые будут вызывать по-разному обозванные функции. Что с ними будет делаться, уже неважно, можно и экспортировать, можно и явно линковать. |
Сообщ.
#4
,
|
|
|
Цитата Qraizer @ KILLER, для перегруженных сущностей нужна декорация имён. Без вариантов. Если они при этом импортируются, то и в таблицах экспорта они должны проходить в декорированном виде. Как вариант, ты можешь заинлайнить – без их экспорта/импорта – простые переходники, которые будут вызывать по-разному обозванные функции. Что с ними будет делаться, уже неважно, можно и экспортировать, можно и явно линковать. Да в принципе меня больше интересовал вопрос с академической стороны, чем с практической. В принципе можно это решить, но не очень наверное переносимо получится, по крайней мере на мсдне пишут -> https://msdn.microsoft.com/en-us/library/s90k71yx.aspx Цитата To prevent this warning, specify the symbol in its decorated form. Run DUMPBIN on the object to see decorated names. Типа с помощью dumbin /export получить декорированное имя двух этих функций и запихнуть это в def файл. Я пробовал брать декорированное имя из ошибки линкера, для 64 битной конфигурации все отработало нормально, для конфигурации х86 не собралось. Потом подумал покумекал что могут мне эти инлайны дать, ведь в таблице экспорта должны быть две версии функции, иначе я не получу адрес нужной мне через какой нибудь GetProcAddress. В итоге вторую функцию просто переименовал. Если бы InstallShield понимал функции с декорированными именами, то я бы убрал def файл. А так, пришлось переименовать функцию )) |
Сообщ.
#5
,
|
|
|
В доке нашел абзац, может поможет:
Цитата If you are exporting functions in a C++ file, you have to either place the decorated names in the .def file or define your exported functions with standard C linkage by using extern "C". If you need to place the decorated names in the .def file, you can obtain them by using the DUMPBIN tool or by using the linker /MAP option. Note that the decorated names produced by the compiler are compiler specific. If you place the decorated names produced by the Visual C++ compiler into a .def file, applications that link to your DLL must also be built using the same version of Visual C++ so that the decorated names in the calling application match the exported names in the DLL's .def file. |
Сообщ.
#6
,
|
|
|
Цитата KILLER @ Возможно декорирование для 64 и 32 бит различается. В таком случае, видимо, надо было в утилиту какой-то ключ дополнительно передать, чтобы он нужное декорированное имя выдал.для 64 битной конфигурации все отработало нормально, для конфигурации х86 не собралось. А надёжнее в link /MAP добавить, в карте имена с использованным декорированием прописываются. Вообще, использовать DLL с экспортом декорированных имён часто неудобно. Поскольку использовать эти DLL можно (без дополнительных телодвижений) только с тем компилятором, которым они построены. Для последующего использования лучше пользоваться советом, который дал Qraizer |