Создание DLL на C ++ для импорта C ++ DLL в VS 2005

Я пытаюсь связать C ++ DLL с новой C ++ DLL, которую я создам,

Я шаг за шагом следовал приведенному ниже руководству и многим другим, но что-то не так: функция GetProcAddress возвращает NULL "http://www.dreamincode.net/forums/topic/118076-dlls-explicit-linking/"

Это прототип функции, которую я пытаюсь вызвать из DLL:

int RemoveAllDataFile (unsigned int id);

функция возвращает 1, поэтому DLL загружается успешно.

typedef int (*funcRemoveAllDataFile) (int);

int load_dll_ARbnet(int x)
{
    /* Retrieve DLL handle.*/
    HINSTANCE hDLL = LoadLibrary("ArbNet2Remote.dll");   
    if (hDLL == NULL)
    {
        return 0;
    }    
    else
    {
    }
    /*Get the function address*/
    funcRemoveAllDataFile RemoveAllDataFile = (funcRemoveAllDataFile)GetProcAddress(hDLL, "RemoveAllDataFile");
    if (RemoveAllDataFile)
    {
        return 2;
    }
    else
    {
        return 1;
    }

}


person Amr Azzam    schedule 16.02.2015    source источник
comment
Изменение имени C ++ при поиске   -  person Ed S.    schedule 16.02.2015


Ответы (2)


Посмотрите на фактический экспорт DLL, например, с помощью инструмента отчетности, такого как TDUMP или аналогичного. Функция, которую вы ищете, не экспортируется как "RemoveAllDataFile", как вы ожидали. Фактически, вместо этого он экспортируется как "_RemoveAllDataFile" или даже как что-то вроде "_RemoveAllDataFile@4".

Если вы компилируете исходную DLL и хотите, чтобы функция экспортировалась как "RemoveAllDataFile", вам придется заключить объявление экспортируемой функции в extern "C", чтобы удалить любое искажение имени C ++ из экспортируемого имени. В зависимости от вашего компилятора C ++ вам также может потребоваться использовать .def файл для удаления начального подчеркивания, налагаемого __cdecl соглашением о вызовах. При использовании связи C некоторые компиляторы C ++ экспортируют __cdecl функции с начальным подчеркиванием (например, Borland), а некоторые - нет (например, Microsoft).

Но если вы не перекомпилируете исходную DLL, у вас нет другого выбора, кроме как посмотреть на экспорт DLL и изменить свой GetProcAddress() вызов, чтобы использовать собственное имя, которое фактически экспортируется.

person Remy Lebeau    schedule 16.02.2015
comment
теперь работает нормально, dll экспортировала функцию как? RemoveAllDataFile @@ YAHI @ Z вместо RemoveAllDataFile. Чтобы получить настоящий экспорт, я использовал virustotal.com, настоящие имена перечислены в разделе Экспорт PE в разделе сведений о файле. онлайн-решение. - person Amr Azzam; 17.02.2015

Функция, которую вы экспортируете из другой DLL, должна быть объявлена ​​extern "C" при использовании исходного кода C ++. Если следует экспортировать либо с файлом .def, либо с использованием __declspec(dllexport):

Вот типичный файл заголовка DLL, который работает с .c или .cpp и обоими соглашениями о вызовах:

#ifdef MYAPI_EXPORTS
#define MYAPI __declspec(dllexport)
#else
#define MYAPI __declspec(dllimport)
#endif

#ifdef __cplusplus
extern "C" {
#endif

MYAPI int __cdecl   func1(int x);
MYAPI int __stdcall func2(int x);

#ifdef __cplusplus
}
#endif

Источник DLL:

#define MYAPI_EXPORTS
#include "x.h"
int func1(int x)
{
    return x*2;
}

int __stdcall func2(int x)
{
    return x*3;
}

И использование:

#include <windows.h>
#include <stdio.h>

typedef int (__cdecl   *FUNC1)(int);
typedef int (__stdcall *FUNC2)(int);
int main()
{

    HINSTANCE hDLL = LoadLibrary("x");
    FUNC1 func1 = (FUNC1)GetProcAddress(hDLL, "func1");
#ifdef _WIN64
    FUNC2 func2 = (FUNC2)GetProcAddress(hDLL, "func2");
#else
    FUNC2 func2 = (FUNC2)GetProcAddress(hDLL, "_func2@4");
#endif
    printf("%d %d\n",func1(5),func2(5));
}

Украшение имени может быть обнаружено с помощью dumpbin /exports <dll>. Обратите внимание, что x64 и x86 различаются. Ниже для x86:

   ordinal hint RVA      name

         2    0 00001010 _func2@4
         1    1 00001000 func1
person Mark Tolonen    schedule 16.02.2015
comment
extern "C" удалит искажение имени C ++, но не _ в начале, для этого нужно использовать .def файл. Таким образом, вам нужно будет использовать extern "C", __declspec(dllexport) и .def все вместе, чтобы экспортировать __cdecl функцию без каких-либо украшений. - person Remy Lebeau; 16.02.2015
comment
Соглашение о вызовах __cdecl (которое использует этот код, поскольку оно является соглашением о вызовах по умолчанию для большинства компиляторов C / C ++, если не настроено иное) по-прежнему выводит начальное подчеркивание, когда extern "C" используется сам по себе (или источник скомпилирован как C вместо C ++). Файл .def необходим для создания экспортируемого псевдонима без подчеркивания. - person Remy Lebeau; 16.02.2015
comment
Как бы то ни было, приведенный выше код работает с файлами .c и .cpp в версиях VS2012 x86 и x64. dumpbin показывает имя без украшений. __stdcall показывает _funcRemoveAllDataFile@4. - person Mark Tolonen; 16.02.2015
comment
Я только что прочитал документацию MSDN для _cdecl: символ подчеркивания (_) перед именами, кроме случаев, когда экспортируются функции __cdecl, использующие связь C. Я не использую VC ++, и это поведение отличается от других компиляторов C ++, которые я использую, которые экспортируют подчеркивание на C-связанные функции. - person Remy Lebeau; 16.02.2015
comment
Да, Microsoft любит отличаться: ^) Даже если оставить подчеркивание, его можно использовать без .def как GetProcAddress(hDll,"_funcRemoveAllDataFile"). Имя имеет начальное подчеркивание, как показано в .obj файле. Это просто то, как Microsoft экспортирует его в таблицу имен DLL. - person Mark Tolonen; 16.02.2015