Использование GetProcAddress, когда имя может быть оформлено
Как правильно использовать GetProcAddress()
на 32-битной DLL? На win32 существует три соглашения о вызовах: cdecl, stdcall и fastcall. Если функция в DLL foo
они будут украшать имя следующими способами _foo
, _foo@N
а также @foo@N
,
Но если автор dll использовал файл.def, то экспортированное имя будет изменено на "foo" без каких-либо украшений.
Это создает проблемы для меня, потому что, если я хочу загрузить foo
из DLL, которая использует stdcall, я должен использовать оформленное имя:
void *h = LoadLibraryEx(L"foo.dll", NULL, 0);
GetProcAddres((HMODULE)h, L"_foo@16");
Или неокрашенный:
void *h = LoadLibraryEx(L"foo.dll", NULL, 0);
GetProcAddres((HMODULE)h, L"foo");
? Должен ли я угадать? Я просмотрел множество 32-битных DLL-файлов (stdcall и cdecl), и все они, похоже, экспортируют недекорированное имя. Но можете ли вы предположить, что это всегда так?
2 ответа
Там действительно нет ярлыка или окончательного правила здесь. Вы должны знать название функции. Обычный сценарий состоит в том, что вы знаете во время компиляции имя функции. В этом случае не имеет значения, является ли экспортированное имя искаженным, украшенным или действительно не связанным с семантическим именем. Функции могут быть экспортированы без имен, по порядковому номеру. Опять же, вам нужно знать, как была экспортирована функция.
Если вам представлен заголовочный файл для библиотеки, и вы хотите сделать ссылку на него с явным связыванием (LoadLibrary
/GetProcAddress
) тогда вам нужно будет узнать названия функции. Используйте такой инструмент, как dumpbin или Dependency Walker, чтобы сделать это.
Теперь другой сценарий, который может привести к тому, что вы зададите вопрос, заключается в том, что вы не знаете имя во время компиляции. Например, имя предоставлено пользователем вашей программы тем или иным способом. Опять же, вполне разумно требовать, чтобы пользователь знал экспортированное имя функции.
Наконец, вы можете проанализировать метаданные PE для исполняемого файла, чтобы перечислить его экспортированную функцию. Это даст вам список имен экспортируемых функций и порядковые номера экспортируемых функций. Это то, что делают такие инструменты, как dumpbin и Dependency Walker.
Если
__declspec(dllexport)
используется во время компиляции и
__declspec(dllimport)
в заголовочном файле, а также
extern "c"
, то эти функции не нужно украшать. В
__declspec
помогает использовать недекорированные имена, но перегрузки функций, пространства имен и классы по-прежнему требуют того же способа их различения.
Обычно объектно-ориентированные функции экспортируются с использованием порядковых номеров функций вместо их декорированных имен. Отобразите порядковый номер как
(char*)(unsigned short)ordinal
, таким образом,
GetProcAddress(module, (char*)(unsigned short)ordinal);
Изменить: в то время как большинство Windows используют UTF-16, GetProcAddress использует UTF-8, поэтому он не может использовать строку широких символов.
GetProcAddress(module, L"foo")
идентичен
GetProcAddress(module, "f");