#c #getprocaddress #dependency-walker
Вопрос:
У меня есть библиотека DLL, и я хочу вызвать в ней функцию. Я проверяю DLL с помощью Dependency Walker, и результат, который я получил, таков:
void U2U_Test(void)
Это код, который я написал, но GetProcAddress()
возвращает значение NULL:
typedef void(*U2U_Test_pointer)();
void check() {
HINSTANCE hGetProcIDDLL1 = LoadLibrary(_T("my_dll.dll"));
if (hGetProcIDDLL1 == NULL)
return;
U2U_Test_pointer addr = (U2U_Test_pointer)GetProcAddress(hGetProcIDDLL1, "U2U_Test");
if (addr == NULL)
return;
return addr();
}
Комментарии:
1. Вы видите искаженное имя. Экспортированное имя должно быть искажено.
2.
GetProcAddress
не врет. Эта функция с именемU2U_Test
не существует в загруженной вами библиотеке DLL. Если вы скажете, что это так, свяжитесь с корпорацией Майкрософт как можно быстрее, так как это ошибка, которая может повлиять на миллионы программ.3. Не связаны, но
return addr();
и в этой функции нет смысла. Функция таковаvoid
. Это должно быть простоaddr();
4. @S. M. вы правы, я должен использовать use ? U2U_Test@@YAXXZ для имени функции, это решает проблему.
5. @PaulMcKenzie вы правы, GetProcAddress не врет, но я искал свою ошибку и с помощью уважаемого S. M. Я нашел свою ошибку.
Ответ №1:
В зависимости от соглашений и используемого компилятора фактическое имя, экспортированное в библиотеку DLL, может не совпадать с тем, которое вы написали в исходном коде. Это явление обычно называют украшением имени или искажением имени.
На самом деле вы гарантированно будете иметь точно такое же имя, только если
- Ваш компилятор соответствует соглашениям на C (возможно, это так)
- Функция экспортируется в C, а не в C . Используйте
extern "C"
, чтобы указать его. - Соглашение о вызове _cdecl (укажите
__cdecl
в объявлении функции)
Например, когда соглашение о вызове __stdcall вместо __cdecl, что характерно для многих библиотек DLL Windows (они часто пишут WINAPI или ОБРАТНЫЙ вызов вместо __sstdcall), имя экспортируемой функции часто имеет суффикс @n, где n-количество байтов, ожидаемых в стеке для параметров. В вашем случае это может быть U2U_Test@0
так . Такие указания, как __declspec(dllimport)
и __declspec(dllexport)
указание компилятору автоматически позаботиться об этом, когда библиотеки DLL импортируются/связываются во время компиляции.
В C сложное оформление имен используется для поддержки методов, перегрузки функций, шаблонов и других функций, и каждый компилятор изобрел сумасшедшие схемы именования, чтобы убедиться, что никогда не будет никакого столкновения. Потому что на уровне DLL нет ни шаблона, ни классов, а только список экспортированных символов, индексированных по их имени или идентификатору. Именно по этой причине большинство библиотек DLL экспортируются в C и поэтому большинство заголовочных файлов объявляют функции, поступающие из DLL внутри extern "C" { ... }
блока.