декорирование имен,__stdcall и __declspec(dllimport) из библиотеки

Тема в разделе "LANGS.C", создана пользователем m0r1arty, 12 дек 2010.

  1. m0r1arty

    m0r1arty New Member

    Публикаций:
    0
    Регистрация:
    31 янв 2009
    Сообщения:
    14
    Доброе время суток всем.

    Имеется библитека asterisk.dll в которой только одна функция asterisk_call(соглашение вызова __stdcall).
    Ф-ция производит вызов номера посредством AMI интерфейса и связывает канал с определенным контекстом/экстеном/приоритетом.

    Пытаюсь импортировать эту ф-цию в программку на C++, используя .lib и .def файлы. Но ничего не выходит.

    Собственно, проблема не в конкретной dll или ф-ции. Нужно как-то отменить декорирование имен в Visual C++ или объяснить линковщику с каким именем в библиотеке связано импортируемое имя ф-ции.

    asterisk.def:

    LIBRARY "asterisk.dll"
    EXPORTS
    asterisk_call
    asterisk_call@44 = asterisk_call
    ?asterisk_call@@YGXPADG00000GEKK@Z = asterisk_call


    C:>lib.exe /DEF:asterisk.def /MACHINE:X86

    main.cpp:

    #include <iostream>
    #include <windows.h>

    #pragma comment(lib,"asterisk.lib")

    extern "C" __declspec(dllimport) VOID WINAPI asterisk_call(PCHAR,WORD,PCHAR,PCHAR,PCHAR,PCHAR,PCHAR,WORD,BYTE,DWORD,DWORD);

    void main(void)
    {
    std::cout<<"Exit..."<<std::endl;
    asterisk_call("",0,"","","","","",0,0,0,0);
    ExitProcess(0);
    }

    Если это скомпилировать и попробовать запустить, то система скажет "Точка входа в процедуру asterisk_call@44 не найдена в библиотеке DLL asterisk.dll". Это и понятно, что там этой функции нет.

    Если использовать __cdecl, то все будет хорошо, за исключением проблем со стеком(что вполне логично) и вылетом по эксцепшену.

    Так же всё будет хорошо и даже работать, если в .def файл добавить ординал ф-ции, тогда вызов будет идти через него.

    Использовать явное LoadLibrary/GetProcAddress не хочется. Хочется, чтобы библитека с ф-цией светились в импорте программы.

    В гугле/на MSDN ничего не нашел, хотя вопрос волнует многих, например http://stackoverflow.com/questions/2393178/creating-an-msvc-import-library-from-a-dll-that-uses-stdcall


    Под конец, вопрос можно сформулировать:
    каким образом компилятор от MS правильно линкует следующую ф-цию

    WINBASEAPI
    DECLSPEC_NORETURN
    VOID
    WINAPI
    ExitProcess(
    IN UINT uExitCode
    );

    // extern "C" __declspec(dllimport) __declspec(noreturn) VOID __stdcall ExitProcess(IN UINT uExitCode);

    если из kernel32.lib тот же _ExitProcess@4 в импорте программы принимает правильный вид ExitProcess(а не ExitProcess@4)?


    Подозреваю, что это или какой-то pragma делается, или __declspec, или где-то лежат настройки для линковки этих системных либ.
     
  2. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    m0r1arty
    о чём вообще речь? о http://www.asterisk.org/ ?
    я не платный саппорт, если о ссыле выше, то у них свой форум
     
  3. m0r1arty

    m0r1arty New Member

    Публикаций:
    0
    Регистрация:
    31 янв 2009
    Сообщения:
    14
    wsd, библиотека как пример. точно так же можно использовать любую ф-цию из kernel32.dll при этом попробовать создать .lib из .def файла и залинковать всё это. вопрос в том, чтобы при соглашении __stdcall линкер прописал в импорт ExitProcess(например, или касаемо моего пример asterisk_call, а не ExitProcess@4 или asterisk_call@44, соотвественно).
     
  4. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Могу дать тулзу которая отрезает _ и @. ^)
    А вообще делаем библиотеку, прописываем секцию экспорта с нужным именем и вуаля, 5 минут работы.
     
  5. m0r1arty

    m0r1arty New Member

    Публикаций:
    0
    Регистрация:
    31 янв 2009
    Сообщения:
    14
    Booster, спасибо, конечно, но тулзы не надо :) Я хочу узнать почему и как из kernel32.lib в конечный exe`шник попадают API с правильными именами :) Узнать и повторить :)
     
  6. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    m0r1arty
    Ну так сделайте проект lib, сделайте def файл в котором будет прописана экспортируемая функция asterisk_call и используйте полученную библиотеку-переходник для подключения оригинальной либы.
     
  7. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Хотя и def даже не нужен. Библиотека создастся и так как надо.
     
  8. osox

    osox New Member

    Публикаций:
    0
    Регистрация:
    13 ноя 2009
    Сообщения:
    280
    m0r1arty
    точно с этим же сталкивался в итоге как я решил создаете проект dll в нем просто прописываете эксопртируемые функции собираете берете оттуда нужный lib и используете в своем проекте все правильно собирается работает а вот если делать как вы то у меня тоже были такие же проблемы как у вас

    //ps
    мне бы тоже было интересно узнать как готовить либы для системных дллок без создания своего проекта dll в нем для нужных апишек прописывания экспорта и изымания оттуда готового lib файла и подключения его к своему проекту
     
  9. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    osox
    Я именно это и имел ввиду.
     
  10. m0r1arty

    m0r1arty New Member

    Публикаций:
    0
    Регистрация:
    31 янв 2009
    Сообщения:
    14
    Спасибо за ответы. Я так понял, что это(какое название ф-ции будет в импорте) зависит от содержимого .lib файла. Следовательно то, что выплевывает на выходе lib.exe не подходит. Видимо надо или "правильную" lib.exe искать или пристальней смотреть на параметры/настройки текущей. На сколько я знаю формат DEF такого не поддерживает.
     
  11. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Только что попробовал lib.exe - всё нормально работает.
    Код (Text):
    1. LIBRARY "asterisk.dll"
    2. EXPORTS
    3. asterisk_call
     
  12. m0r1arty

    m0r1arty New Member

    Публикаций:
    0
    Регистрация:
    31 янв 2009
    Сообщения:
    14
    Booster
    Странно. У вас не возникло при линковке ошибки "error LNK2019: unresolved external symbol __imp__asterisk_call@44 referenced in function _main"?

    Код изменяли? lib.exe из какой студии? :)

    Можете asterisk.lib выложить?
     
  13. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Ошибок никаких нету.
    lib.exe пробовал из 2005 и 2010 студий.
    В def добавил дополнительную функцию для чистоты эксперимента.
     
  14. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Никаких параметров и @ в def писать не надо.
    В проге использующей dll примерно так: extern "C" int asterisk_call(int);
     
  15. m0r1arty

    m0r1arty New Member

    Публикаций:
    0
    Регистрация:
    31 янв 2009
    Сообщения:
    14
    да, но тогда будет срывать стек из-за __cdecl(по умолчанию). да и ф-цию не вызвать без совпадения кол-ва и типов аргументов. у меня VS2010 по прежнему не находит зависимости.
     
  16. m0r1arty

    m0r1arty New Member

    Публикаций:
    0
    Регистрация:
    31 янв 2009
    Сообщения:
    14
    Получилось :)

    Всем кому интересно(osox) объясняю как:

    1. формируем INC файл asterisk.inc
    Код (Text):
    1. asterisk_call PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
    44 байта(_asterisk_call@44) - это 11 DWORD

    2. берем из пакета MASM32 утилиту INC2L.EXE

    3. скармливаем наш инклюд c:\masm32\include\INC2L.EXE asterisk.inc

    4. на выходе правильный готовый .lib файл

    Еще раз всем спасибо.
     
  17. la2elpy

    la2elpy New Member

    Публикаций:
    0
    Регистрация:
    1 дек 2007
    Сообщения:
    6
    Апну :)
    Кстати если polib.exe скормить например такой def:

    LIBRARY user32
    EXPORTS
    _MessageBoxA@16

    То, если потом использовать полученную lib, в импорт экзешника пишется чистое название MessageBoxA без "_" и @n. И все работает прекрасно.
    В lib какой то флаг видимо выставляется - в каком виде в импорт писать название функции: с декорацией или без.