Creating a shared library for both managed and unmanaged environment
-
Hi,
I'm planning to create a dll design to use for both managed (.NET) and unmanaged (Delphi) environment. The final image has not to be the same. I can build them differently. And I even can have some different and platform dependent wrapper code, no problem. I just want to have a singular cross platform business logic and infrastructure code.
What's the best way to achieve this? I know there are ActiveQt and Wrapper for C++/CLI but as I'm not experienced in this area, it would be better to hear from experienced devs.
Say, we'd selected the proposed style. Would it be possible to use some structs, enums etc between the caller and our dll or do we have to use only standard types like int, float, double etc.
Thanks in advance.
/// Murat -
What I normally do is create the pure C++ class, using custom types and Qt Types then I build a wrapper around it using C++/CLI using some utilities to convert custom types (QString to String^ for example)
For example:
Foo.h
#include <QString> class Foo{ Foo():m_bar("Bar"){} Foo(const Foo& val):m_bar(val.m_bar){} const QString& getBar() const { return m_bar;} void setBar(const QString& val){m_bar=val;} QString m_bar; }
Converters.h
#include <vcclr.h> #include <msclr\marshal_cppstd.h> namespace ManagedVersions { QString String2QString(String^ a) { return QString::fromStdWString(msclr::interop::marshal_as<std::wstring>(a)); } String^ QString2String(const QString& a) { return gcnew String(a.toStdWString.c_str()) } }
ManFoo.h
#include "Converters.h" #include "Foo.h" #include <vcclr.h> using namespace System; namespace ManagedVersions { public ref class ManFoo { internal: Foo* Unmanaged; ManFoo(const Foo& a){Unmanaged=new Foo(a);} public: property String^ Bar{ String^ get(){return QString2String(Unmanaged->getBar());} void set(String^ a){Unmanaged->setBar(String2QString(a));} } ManFoo(){Unmanaged=new Foo();} ManFoo(const ManFoo% a){Unmanaged=new Foo(*(a.Unmanaged));} ManFoo(ManFoo^ a){Unmanaged=new Foo(*(a->Unmanaged));} !ManFoo() { if (Unmanaged){ delete Unmanaged; Unmanaged = nullptr; } } ~ManFoo() { this->!ManFoo(); GC::SuppressFinalize(this); } }; }
(I omitted the include guards there)
There are caveats however, for example when compiling with clr QClipboard doesn't work anymore (or maybe now it does https://bugreports.qt.io/browse/QTBUG-38398 )
-
Thanks VRonin, your example is much better comparing to the official documentation. Could you give me also some information about the managed side?
For example, say we have a struct in Foo.h. What do we have to do to use it directly from .NET? Do we have to also use converter methods for it? (Like having a similar class in ManFoo.h and exchanging members with the native struct from Foo.h).
Cheers,
-
I'd like to include some final information to make this thread history.
I had to use different classes (structs) for managed and native sides since they were not the same for the C++/CLI compiler. But I used a simple trick to define ingredients of these structs. This way I was able to sync the information between the managed and native world.
Of course I had to use some wrapper code since the managed and native structs were living on different worlds.