C ++ DLL, вызывающая функцию, реализованную в потребляющем приложении - PullRequest
2 голосов
/ 03 ноября 2011

Как вызвать функцию после реализации (например, указатели функций или виртуальные функции, реализованные в приложении-потребителе) со сложным типом возврата из функции DLL?

Я попробовал следующую схему, но получил ошибки.

test.h:

#ifdef _DLL_IMPL
#define DLL_EXPORT __declspec(dllexport)  
#else  
#define DLL_EXPORT __declspec(dllimport)  
#endif
typedef string (*test)(void);
extern DLL_EXPORT test __test;
DLL_EXPORT int launch();

test.cpp:

#define _DLL_IMPL
#include "Test.h"
test __test = 0;
int launch()
{
    string a = __test();
    return 0;
}

И приложение-потребитель выглядит так:

main.cpp:

#include "Test.h"
#pragma comment(lib, "Test.lib")
string test_impl()
{
    string a = "test";
    return a;
}
int main(int args, char** argv)
{
    __test = &test_impl;
    return launch();
}

И я получил следующее сообщение об ошибке:

Windows has triggered a breakpoint in TestRun.exe.

This may be due to a corruption of the heap, which indicates a bug in
TestRun.exe or any of the DLLs it has loaded.

This may also be due to the user pressing F12 while TestRun.exe has focus.

The output window may have more diagnostic information.

Я не знаю, что именно происходило. Ошибка также произошла, когда я попытался вернуть тип указателя на символ, который был бы создан в приложении-потребителе с использованием оператора new и был бы освобожден в функции DLL с помощью оператора delete [].

Может кто-нибудь объяснить причину возникновения ошибки и предложить мне какое-нибудь решение этой схемы? Спасибо!

Ответы [ 4 ]

1 голос
/ 03 ноября 2011

Передача объектов C ++ между exe и dll на самом деле не очень хорошая идея, особенно если объект основан на шаблонном классе и / или имеет встроенные методы, и даже более того, если объект выделяет память внутри.Если вам нужен такой интерфейс между вашим приложением и библиотекой, то я рекомендую вам переключить вашу dll на статическую библиотеку, тогда вы избежите большинства проблем.

Если вам нужно сохранить dll как dll, то я рекомендую передавать только нативные типы между exe и dll.В вашем примере переключение всех случаев использования string на char*, скорее всего, решит проблему сбоев.

Также примите хороший совет от Джима Роудса и объявите явное соглашение о вызовах, даже если вы обнаружили, что это не так.проблема в данном конкретном случае.

0 голосов
/ 04 ноября 2011

Что вы действительно хотите экспортировать / импортировать, не ясно.Вы экспортируете test_impl из main.cpp и импортируете запуск в main.cpp из test.cpp

В любом случае, вам, вероятно, следует также экспортировать классы (std :: string).

Следующий код работает отлично:

//test.cpp
typedef __declspec(dllimport)    std::string        (*test)(void); 

    extern __declspec(dllexport)  test __test;

    test __test = 0; 

extern __declspec(dllexport)    int launch() {      std::string a = __test();     
std::cout << a << std::endl ; 
return 0; } 

// main.cpp 
typedef __declspec(dllexport)    std::string        (*test)(void); 
extern __declspec(dllimport)  test __test;
extern __declspec(dllimport)  test __test;

__declspec(dllimport)  int launch(); 

__declspec(dllexport) 
std::string test_impl() {  
    std::string a = "test";   
    return a; } 

int main(int args, char** argv) {  
    __test = &test_impl;    
    return launch(); } 

Убедитесь, что оба проекта скомпилированы с одной и той же моделью (/ MTd, / Mt)

0 голосов
/ 03 ноября 2011

Скорее всего, вы связываетесь с различными версиями библиотек времени выполнения C, предотвращая использование общей кучи. Убедитесь, что и приложение, и dll связаны с одним и тем же «вкусом» (динамическим или статическим) библиотек времени выполнения C - если вы не уверены, какой из них выбрать, установите для них обоих значение dynamic.

См. Также Странные проблемы с новым / удалением в приложении, которое использует мою DLL .

0 голосов
/ 03 ноября 2011

Возможно, у вас несоответствие соглашения о вызовах.Возможно, строка test_impl () должна быть строкой __stdcall test_impl ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...