Re: dll и exe, makeMyClass
От: Roman Odaisky Украина  
Дата: 05.05.08 17:56
Оценка: 2 (1)
Здравствуйте, alzt, Вы писали:

A>Какие проблемы могут быть с подобным подходом:


Лучше всего полностью разделять код на C и на C++.

Вот так надежнее всего, но писать много:

runnable.export.h
struct CRunnable;

extern "C"
{
    void c_run(struct CRunnable *);
    void c_destroy(struct CRunnable const *);
}

runnable.export.hpp
class Runnable
{
public:
    virtual ~Runnable()
    {
    }

    void run();

private:
    virtual void implRun() = 0;
};

runnable.export.cpp
#include "runnable.export.hpp"
#include "runnable.export.h"

void Runnable::run()
{
    pre();
    implRun();
    post();
}

extern "C" void c_run(CRunnable* c)
{
    reinterpret_cast<Runnable *>(c)->run();
}

extern "C" void c_destroy(CRunnable const* c)
{
    delete reinterpret_cast<Runnable const *>(c);
}

runnable1.export.h
#include "runnable.export.h"

extern "C" struct CRunnable* c_makeRunnable1();

runnable1.hpp
#include "runnable.hpp"

class Runnable1: public Runnable
{
private:
    void implRun();
};

runnable1.cpp
#include "runnable1.hpp"
#include "runnable1.export.h"
void Runnable1::implRun()
{
    . . .
}

CRunnable* c_makeRunnable1()
{
    return reinterpret_cast<CRunnable *>(implicit_cast<Runnable *>(new Runnable1()));
}

runnable2.export.h
#include "runnable.export.h"

extern "C" struct CRunnable* c_makeRunnable2();

runnable2.hpp
#include "runnable.hpp"

class Runnable2: public Runnable
{
private:
    void implRun();
};

runnable2.cpp
#include "runnable2.hpp"
#include "runnable2.export.h"
void Runnable2::implRun()
{
    . . .
}

extern "C" CRunnable* c_makeRunnable2()
{
    return reinterpret_cast<CRunnable *>(implicit_cast<Runnable *>(new Runnable2()));
}



runnable.import.hpp
struct CRunnable;

class Runnable
{
public:
    explicit Runnable(CRunnable *);
   ~Runnable();

    void run();

private:
    CRunnable* m_impl;
};

runnable.import.cpp
#include "runnable.export.h"

Runnable::Runnable(CRunnable* c): m_impl(c)
{
}

Runnable::~Runnable()
{
    c_destroy(m_impl);
}

void Runnable::run()
{
    c_run(m_impl);
}

runnable1.import.hpp
#include "runnable.import.hpp"

Runnable makeRunnable1();

runnable1.import.cpp
#include "runnable1.export.h"
Runnable makeRunnable1()
{
    return Runnable(c_makeRunnable1());
}

runnable2.import.hpp
#include "runnable.import.hpp"

Runnable makeRunnable2();

runnable2.import.cpp
#include "runnable2.export.h"
Runnable makeRunnable2()
{
    return Runnable(c_makeRunnable2());
}
До последнего не верил в пирамиду Лебедева.
Re: dll и exe, makeMyClass
От: alsemm Россия  
Дата: 05.05.08 17:58
Оценка: 2 (1)
Здравствуйте, alzt, Вы писали:

A>Добрый вечер.


A>Какие проблемы могут быть с подобным подходом:

A>[ccode]
A>//код dll
A>#define EXTERNAL __declspec(dllexport)

A>class EXTERNAL IMyInterface

A>{
A>public:
A> virtual void Method1()=0;
A> virtual void Method2()=0;
A>};
...
Обязательно кто-нибудь в exe сделает delete на полученном из dll IMyInterface*

http://aegisknight.org/cppinterface.html — прочитайте обязательно, очень полезная статья про то как правильно писать классы для экспорта из dll.

Алексей
Re[4]: dll и exe, makeMyClass
От: Erop Россия  
Дата: 05.05.08 18:37
Оценка: 1 (1)
Здравствуйте, alzt, Вы писали:

A>>dll — MS2008,

A>>exe — GCC
A>dll — имелся в виду компилятор в составе MSVS2005.

AFAIK всё будет хорошо.
Чтобы было ещё лучше, стоит сделать деструктор твоего интерфейса protected и невертуальным.

Ещё можно извести функцию по разрушению объектов, добавив в интерфейс метод Release.

А вообще смотри на то, как на том и на другом компиляторе надлежит реализовывать COM-интерфейсы.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: dll и exe, makeMyClass
От: Roman Odaisky Украина  
Дата: 06.05.08 08:01
Оценка: +1
Здравствуйте, alzt, Вы писали:

A>Писать действительно много. А есть ли смысл разделять этот код, если планируется использовать только С++?


Нет, наверное. См. ссылку ниже.
Вообще, было бы хорошо иметь какой-то препроцессор, который бы сам генерировал код для экспорта на C и обертки в обе стороны.

A>Хотелось бы наоборот использовать на полную stl и boost.


А вот эти вещи лучше не передавать через границы модулей. Шаблоны вообще не получится, исключения будут очень проблематичны, соглашения, отличные от extern "C", будут вызывать проблемы при смене компилятора.
До последнего не верил в пирамиду Лебедева.
Re[3]: dll и exe, makeMyClass
От: alsemm Россия  
Дата: 06.05.08 09:15
Оценка: +1
...
A>Хотелось бы наоборот использовать на полную stl и boost.
Вот вы упрямый-то Ссылку на статью вам привел — читать не стали, ок, вот вам цитата:
That's about it. In closure, I'll enumerate guidelines to keep in mind when creating C++ interface. You can look back on this as a reference or use it to help solidify your knowledge.

    * All interface classes should be completely abstract. Every method should be pure virtual. (Or inline... you could safely write inline convenience methods that call other methods.)
    * All global functions should be extern "C" to prevent incompatible name mangling. Also, exported functions and methods should use the __stdcall calling convention, as DLL functions and COM traditionally use that calling convention. This way, if a user of the library is compiling with __cdecl by default, the calls into the DLL will still use the correct convention.
    * Don't use the standard C++ library.
    * Don't use exception handling.
    * Don't use virtual destructors. Instead, create a destroy() method and an overloaded operator delete that calls destroy().
    * Don't allocate memory on one side of the DLL boundary and free it on the other. Different DLLs and executables can be built with different heaps, and using different heaps to allocate and free chunks of memory is a sure recipe for a crash. For example, don't inline your memory allocation functions so that they could be built differently in the executable and DLL.
    * Don't use overloaded methods in your interface. Different compilers order them within the vtable differently.


Есть еще один момент, который в этой статье не учтен: sizeof(тип возвращаемого значения из экпортируемой функции) <= sizeof(int). Это из личного опыта. Проблема тут в том, что соглашения о вызовах (cdecl, stdcall) не регламентируют то как возвращать значение из функции и все компиляторы, если результат не влезает в eax делают это по разному.

Очень советую ни один из пунктов не игнорировать.

Алексей
dll и exe, makeMyClass
От: alzt  
Дата: 05.05.08 16:33
Оценка:
Добрый вечер.

Какие проблемы могут быть с подобным подходом:
//код dll
#define EXTERNAL __declspec(dllexport)

class EXTERNAL IMyInterface
{
public:
    virtual void Method1()=0;
    virtual void Method2()=0;
};

extern "c"
{
EXTERNAL IMyInterface * makeMyClass();
EXTERNAL void destroyMyClass(IMyInterface *);
};

?

Использование в программе, которая динамически загружает dll
//получить адреса функций makeMyClass, destroyMyClass
//...

IMyInterface * myClass =  makeMyClass();
myClass->Method1();
destroyMyClass(myClass);


Компиляторы, использованные для создания dll и exe разные.
Re: dll и exe, makeMyClass
От: Erop Россия  
Дата: 05.05.08 16:42
Оценка:
Здравствуйте, alzt, Вы писали:

A>Компиляторы, использованные для создания dll и exe разные.

1) Экспортировать IMyInterface не надо
2) Могут быть проблемы с наличием/отстуствием RTTI на разных концах
3) Что за копиляторы?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: dll и exe, makeMyClass
От: alzt  
Дата: 05.05.08 16:55
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, alzt, Вы писали:


A>>Компиляторы, использованные для создания dll и exe разные.


E>3) Что за копиляторы?


dll — MS2008,
exe — GCC
Re[3]: dll и exe, makeMyClass
От: alzt  
Дата: 05.05.08 16:59
Оценка:
Здравствуйте, alzt, Вы писали:

A>Здравствуйте, Erop, Вы писали:


E>>Здравствуйте, alzt, Вы писали:


A>>>Компиляторы, использованные для создания dll и exe разные.


E>>3) Что за копиляторы?


A>dll — MS2008,

A>exe — GCC

dll — имелся в виду компилятор в составе MSVS2005.
Re[2]: dll и exe, makeMyClass
От: alzt  
Дата: 06.05.08 07:14
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Здравствуйте, alzt, Вы писали:


A>>Какие проблемы могут быть с подобным подходом:


RO>Лучше всего полностью разделять код на C и на C++.


RO>Вот так надежнее всего, но писать много:


Писать действительно много. А есть ли смысл разделять этот код, если планируется использовать только С++?
Хотелось бы наоборот использовать на полную stl и boost.
Re[4]: dll и exe, makeMyClass
От: alzt  
Дата: 06.05.08 09:57
Оценка:
Здравствуйте, alsemm, Вы писали:

A>...

A>>Хотелось бы наоборот использовать на полную stl и boost.
A>Вот вы упрямый-то Ссылку на статью вам привел — читать не стали, ок, вот вам цитата:
A>
A>That's about it. In closure, I'll enumerate guidelines to keep in mind when creating C++ interface. You can look back on this as a reference or use it to help solidify your knowledge.

A>    * All interface classes should be completely abstract. Every method should be pure virtual. (Or inline... you could safely write inline convenience methods that call other methods.)
A>    * All global functions should be extern "C" to prevent incompatible name mangling. Also, exported functions and methods should use the __stdcall calling convention, as DLL functions and COM traditionally use that calling convention. This way, if a user of the library is compiling with __cdecl by default, the calls into the DLL will still use the correct convention.
A>    * Don't use the standard C++ library.
A>    * Don't use exception handling.
A>    * Don't use virtual destructors. Instead, create a destroy() method and an overloaded operator delete that calls destroy().
A>    * Don't allocate memory on one side of the DLL boundary and free it on the other. Different DLLs and executables can be built with different heaps, and using different heaps to allocate and free chunks of memory is a sure recipe for a crash. For example, don't inline your memory allocation functions so that they could be built differently in the executable and DLL.
A>    * Don't use overloaded methods in your interface. Different compilers order them within the vtable differently.
A>


A>Есть еще один момент, который в этой статье не учтен: sizeof(тип возвращаемого значения из экпортируемой функции) <= sizeof(int). Это из личного опыта. Проблема тут в том, что соглашения о вызовах (cdecl, stdcall) не регламентируют то как возвращать значение из функции и все компиляторы, если результат не влезает в eax делают это по разному.


A>Очень советую ни один из пунктов не игнорировать.


Придётся довольствоваться спартанским минимумом.
За статью спасибо, пока проглядел только вскользь — времени не было.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.