GetProcAddress не находит функцию в DLL

#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" { ... } блока.