I'm looking to implement a plugin architecture into our current application (Unix, C++) and have been reviewing the options (pending approval) within the Boost libraries.
Edit: I'm looking to dynamically add classes at runtime.
Boost.Plugin
Boost.Reflection
Boost.Extension
I was wondering what everyones experience/opinion is on these and other implementations.
Eh. We just used dlopen and dlsym along with a pair of extern "C" static functions that must be defined in the dll
extern "C" static plugin* create( arg_pack* );
extern "C" static errno_t destroy( plugin* );
Have a plugin-manager look for ".dll" or ".so" files and load them into a
map<string, pair< plugin*(*)(arg_pack*), errno_t(*)(plugin*)> >
You can then lookup a plugin based on a name (the string above) and get it's 'constructor' or 'destructor'
see also: gmodule
You can not load classes at run-time as C++ is a compiled language and classes do not exist at run-time. Objects (instances of classes) do.
What you can do is load shared libraries at run-time and make them create objects of a certain interface.
Minimal plug-in implementation would define the interface of your plug-in and the interface of the factory function that is going to create objects with that interface. You are going to load the shared library at run-time, find the factory function with a certain name, and call the factory function to create an object. Then you use that object though the interface:
// plugin.h start
#include <memory>
struct PlugIn // interface
{
virtual ~PlugIn() = 0;
virtual void doSomething() = 0;
};
extern "C" {
typedef std::auto_ptr<PlugIn> PlugInFactoryFn();
// A plugin .so must export this one factory function.
std::auto_ptr<PlugIn> createPlugIn();
}
// plugin.h end
// somewhere in you application
#include "plugin.h"
#include <assert.h>
#include <dlfcn.h>
std::auto_ptr<PlugIn> loadPlugIn(char const* filename)
{
void* so = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
assert(so);
void* factory_function = dlsym(so, "createPlugIn");
assert(factory_function);
return reinterpret_cast<PlugInFactoryFn*>(factory_function)();
}
int main()
{
std::auto_ptr<PlugIn> a(loadPlugIn("a.so"));
std::auto_ptr<PlugIn> b(loadPlugIn("b.so"));
a->doSomething();
b->doSomething();
}
Related
I have implemented singleton of Meyers and four function to work with it. For example:
//A.h
class A
{
private:
Device d;
public:
A(){//...}
~A(){d.release();}
}
My class singleton Meyers
//Controller.h
class Controlle
{
private:
//some members
A m_member;
Controller();
Controller(const Controller&);
Controller& operator=(const Controller&);
public:
static Controller& GetInstance()
{
static Controller instance;
return instance;
}
}
And interface for working the class of Controller
extern "C" API Result InitDevice(const ParamsDevice* param);
extern "C" API Result InitAlgorithm(const ParamAlgorithm* param);
extern "C" API Result Operation_1();
extern "C" API Result Operation_2();
I build the library and get the Controller.dll and Controller.lib files. Library is shared lib.
Then I create a program where Controller.dll is used (implicit). Runtime library exception is thrown after program termination. I compiled the library in debug to check where the exception is thrown from.
I am getting the exception from comip.h file from method Release() class
template<typename _IIID> class _com_ptr_t
{
public:
// Declare interface type so that the type may be available outside
// the scope of this template.
//
typedef _IIID ThisIIID;
typedef typename _IIID::Interface Interface;
........
// Provides error-checking Release()ing of this interface.
//
void Release()
{
if (m_pInterface == NULL) {
_com_issue_error(E_POINTER);
}
else {
m_pInterface->Release();
m_pInterface = NULL;
}
}
}
I think that when the program terminates, the resources of static objects that are used in the library are incorrectly released. If I replace the singelton Meyers with a classic singelton and create methods for explicitly freeing up the memory of a static pointer, then everything works well. Could you help me explain this effect?
I think there is an answer to my question, but it is not complete for me and I cannot understand
https://stackoverflow.com/a/50644725/13970084
P.S. Sorry for my English. English isn't my native language.
I read through this excellent summary about dll boundaries in c++.
I wrote an example implementation in a single project.
main.cpp
#include <iostream>
#include <memory>
#include <functional>
#include "Interface.hpp"
typedef std::shared_ptr<Interface> IPTR;
int main()
{
IPTR ptr = std::shared_ptr<Interface>(MakeInterface(), std::mem_fn(&Interface::Release));
std::cout << ptr->Foo(4) << "\n";
}
Interface.hpp
#define MyAPI /*export/import*/
#define APIENTRY __stdcall
struct MyAPI Interface
{
virtual int Foo(int n) = 0;
virtual void Release() = 0;
};
extern "C" MyAPI Interface* APIENTRY MakeInterface();
Interface.cpp
#include "Interface.hpp"
struct InterfaceImpl : Interface
{
virtual int Foo(int n){ return n; }
virtual void Release(){ delete this; }
};
extern "C" MyAPI Interface* APIENTRY MakeInterface()
{
return new InterfaceImpl{};
}
My questions are
Can I move the smart pointer declaration into the header without running into C++ dll issues?
Is it correct to call delete this in the Release method?
1.) No.
extern "C" MyAPI Interface* APIENTRY MakeInterface()
{
return new InterfaceImpl{};
}
This new is used from the dll-runtime and can be incompatible with new from the executable. Destroying the object by delete (executable) may not work due to different memory managers. Rule of thumb: If you provide a create/make-function (factory) then you should provide a destroy/free/delete function. Your Release-method will work but is on a different abstraction level than MakeInterface. Rule of 2 thumbs: Export independent standard layout types in combination with pimpl.
2.) Yes.
The Method that you use is what we use at job at it works.
One thing you must pay attention is to pass only C data type of at most pod as argument of your interface.
If you didn't you may incur with memory issue.
For example if you define a function in your interface with a string argument:
struct Mapi Interface
{
void wrong(string& a_string)=0
};
you may have trouble if you compile the client and dll with a different STL version (Think a new version of dll, recompiled vith vs2015 but the client remain old, compiled with vs6).
In this example I pass a ref to string. The initial buffer of the string is allocated by the client.
Now in the dll you assign a new value to a_string, a value big enough to need reallocation.
In this way you free the initial buffer inside dll context. If the heap manager was different (different crt) you have memory issue
I am told to import my writen class in C++ into a dll and then use that dll in a c# application. Following this guide I created the dll, but I can't simply use it in a C# application since there are some issues concerning it:
What should I place for the return type of my factory function?
What is the equivalent of const wchar_t* which is my constructors argument type?
How can I retrieve and use my functions return type which is of type vector< wstring>?
These are the problems that prevent me from using my C++ DLL inside my C# applications. I was told that I need to create a wrapper with C++/CLI and then use that inside my C#. But sadly I have no idea about it, I don't know C++.net.
The only thing that currently seems to be a bit more sensational to me is to make it somehow compatible with C and then create a C DLL and use that in my C# application. I have read that in C, class object pointers are accessible through HANDLEs, so I thought that would be good idea to get things going without a lot of changes.
So the question is how can I use Handles to access my class objects in C and use them? And how can I convert a vector<wstring> to its C counterpart?
If I want to use CLI to create a wrapper (DLL?) for my C++ DLL, to be used in other dotnet apps what should I do?
In order to make a C wrapper for a C++ class to be used in for example a C# application you can do the following.
In Visual Studio choose Win32 Console Application and Enter a name, Then click next and on the next pane choose DLL and click finish. When you are done you are represented with a DLL project including 3 files.
testdll.h
testdll.cpp
dllmain
Delete everything that exists inside your testdll.h and testdll.cpp files and copy the following contents to each respectively. Add these lines to your testdll.h
// Our C wrapper for creating a dll to be used in C# apps
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the TESTDLL_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// TESTDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif
extern "C"
{
TESTDLL_API int OurTestFunction(int x, int y);
}
It is inside this extern "C" block where you define your interface, functions to access your class member functions.Note the TESTDLL before the function prototype. All of your functions must be proceeded by that.
Add these to your testdll.cpp file:
#include "testdll.h"
#include "ourClass.h"
#define DLL_EXPORT
extern "C"
{
OurClass ourObject;
TESTDLL_API int OurTestFunction(int x, int y)
{
return ourObject.Add(x,y);
}
}
You compile this and get a C based dll which can be used in a C# application.
There are couple of things to notice though, The more important ones are:
You need to understand that the code you use as a proxy- i mean
function definition inside your testdll.h, must only use C
compatible types, it is C after all not C++.
is that you would want to be able to allocate new objects of your
class instead of just using one global object to access all methods.
For this, if you need to pass your class objects between member functions, you need to first convert it to a void* which C can understand and then pass it and use it to access your member functions of whatever.
For example I would have something like this inside my testdll.h in order to make user capable of managing the objects indirectly:
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif
extern "C"
{
TESTDLL_API int OurTestFunction(int x, int y);
TESTDLL_API void* CreateHandle();
TESTDLL_API void* GetCurrentHandle();
TESTDLL_API void DisposeCurrentHandle();
TESTDLL_API void SetCurrentHandle(void* handle);
TESTDLL_API void* GetHandle();
TESTDLL_API void DisposeHandle(void*);
TESTDLL_API void DisposeArrayBuffers(void);
}
And inside my testdll.cpp I would define them as :
#include "testdll.h"
#include "ourClass.h"
#define DLL_EXPORT
extern "C"
{
OurClass *ourObject;
TESTDLL_API int OurTestFunction(int x, int y)
{
//return ourObject.Add(x,y); -- not any more !!
ourObject = reinterpret_cast<OurClass *>(GetHandle());
}
//Handle operations
TESTDLL_API void* CreateHandle()
{
if (ourObject == nullptr)
{
ourObject = new OurClass ;
}
else
{
delete ourObject ;
ourObject = new OurClass ;
}
return reinterpret_cast<void*>(ourObject);
}
TESTDLL_API void* GetCurrentHandle()
{
return reinterpret_cast<void*>(ourObject );
}
TESTDLL_API void DisposeCurrentHandle()
{
delete ourObject ;
ourObject = nullptr;
}
TESTDLL_API void SetCurrentHandle(void* handle)
{
if (handle != nullptr)
{
ourObject = reinterpret_cast<OurClass *>(handle);
}
else
{
ourObject = new OurClass ;
}
}
//factory utility function
TESTDLL_API void* GetHandle()
{
void* handle = GetCurrentHandle();
if (handle != nullptr)
{
return handle;
}
else
{
ourObject = new OurClass ;
handle = reinterpret_cast <void*>(ourObject );
}
return handle;
}
CDLL_API void DisposeHandle(void* handle)
{
OurClass * tmp = reinterpret_cast<OurClass *>(handle);
delete tmp;
}
TESTDLL_API void DisposeArrayBuffers(void)
{
ourObject = reinterpret_cast<OurClass *>(GetHandle());
return ourObject ->DisposeBuffers();//This is a member function defined solely for this purpose of being used inside this wrapper to delete any allocated resources by our class object.
}
}
And when we compile this Dll, we can easily work with it inside our C# application. Before being able to use our functions defined in this dll we need to use appropriate [ImportDll()]. So for our TestDll we would write:
[DllImport(#"TestDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int OurTestFunction(int firstNumber,int secondNumber);
And finally use it like:
private void btnReadBigram_Click(object sender, EventArgs e)
{
int x = OurTestFunction(10,50);
MessageBox.Show(x.ToString());
}
This is all I did to make my C++ class member functions accessible inside a C# application without any hassle.
Note:
When compiling your C# application make sure you have chosen the x86 Platform for compiling your project not AnyCpu.You can change your platform through properties.
Note 2:
For knowing how to create a C++/CLI wrapper for your native C++ class read this: C++/CLI wrapper for your native C++ class.
Using a native C++ class directly from C# is technically possible, but it's not trivial, and it's rarely even a good idea. For starters, you have to know the names to use to import from the DLL, which will be the names after C++ name-mangling. You also can't directly access things like vector from C#.
There are basically two good options:
The first is to write a DLL with a C interface that uses only types that can be marshalled into CLR types. You may use pointers along with the IntPtr type, but you can't really dereference those pointers. You can pretty much just store them in your C# code and then pass them back to the native DLL when needed. And you can also use simple struct types as long as you don't need deep copy to work on them. This option involves using P/Invoke.
The second option is to write a mixed-mode C++/CLI assembly that implements all the logic that needs to access your native code. This assembly can directly access classes and data from your C# code and also directly access your native code, although you should be forewarned that there are annoying breaks where you can't mix the two. For example, a ref class in C++/CLI can't have a shared_ptr member. However, it can have a raw C++ pointer as a member. A (mixed-mode) native class can also have access to a CLR handle type and make calls into the C# code through this. This option involves using C++ Interop.
It's worth noting that you could also go the other way with C++ Interop. You could have your C# code access a mixed-mode C++/CLI assembly that provides a .NET interface to some native code. However, you will still have to do some translation in this case so it's not hugely better than the first option.
A full tutorial on C++ Interop would be rather lengthy. I suggest you read up here and do some further investigation of C++ Interop on Google.
C++/CLI introduces managed objects, for which the pointer token * should be replaced with a ^, and a 'new' should be replaced with 'gcnew', you don't need to delete these objects when you're done with them, they'll be garbage collected, [edit] managed classes have a ref keyword in their definition [/edit].
Wrapping the C++ MyClass class in a C++/CLI wrapper class WrapperCLass could look something like this:
#include <stdio.h>
class MyClass
{
public:
void ShowStuff(const wchar_t *a)
{
wprintf(a);
}
};
public ref class WrapperClass
{
MyClass *wrapped;
public:
WrapperClass()
{
wrapped = new MyClass;
}
~WrapperClass()
{
delete wrapped;
}
void ShowStuff(IntPtr string)
{
wrapped->ShowStuff((const wchar_t *)string.ToPointer());
}
};
If you generate a dll with this, you'll be able to use it as a reference in your C# project
and you won't have to use the factory function mechanism.
In C++/CLI are available, so const wchar_t * is as wel.
To convert a System::String to a const wchar_t * you could use something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Client
{
class Program
{
static void Main(string[] args)
{
WrapperClass w = new WrapperClass();
IntPtr tmp;
w.ShowStuff(tmp = System.Runtime.InteropServices.Marshal.StringToHGlobalUni("Test"));
System.Runtime.InteropServices.Marshal.FreeHGlobal(tmp);
}
}
}
(There could very well be better ways to do this...)
For your return type you'll have to do the conversion in your wrapper class. Make some .net collection, iterate through your vector, convert the wstring to a System::String, and add it to the .net collection, and return that.
I'm creating a helper to create multiple inheritance between C++ classes and Lua objects. Because Lua store C/C++ user objects as void *, it's hard to do safe casts when you retrieve objects.
For instance,
if you have
class A { }
class B { }
class C : public A, public B { }
And you pass an object of type C to Lua, you pass the address of the C instance, when you need to cast it to B, the C++ compiler will automatically align the pointer to the position of B in C and thus, it's not safe to cast the void * pointer from C to B directly.
To avoid this issue, I use a kind of converter. In Lua, the objects contains their name as a string, so when you need to cast the object from type to an other type, it uses the converter like this:
converters["B"]["C"](mypointer, myresultpointer);
This is the class that helps creating these converters :
// Common.h
#include <functional>
#include <memory>
#include <unordered_map>
#include <string>
typedef std::function<void (void *, void *)> LuaConverter;
typedef std::unordered_map<
std::string,
std::unordered_map<
std::string,
LuaConverter
>
> LuaConverters;
class LuaeClass {
public:
static LuaConverters converters;
public:
template <class From, class To>
static void createConverter(const std::string &fromName,
const std::string &toName)
{
converters[toName][fromName] = [&] (void *ptr, void *result) -> void {
std::shared_ptr<From> *from = static_cast<std::shared_ptr<From> *>(ptr);
*((std::shared_ptr<To> *)result) = std::static_pointer_cast<To>(*from);
};
}
};
This class is compiled as static library to be used many times in the project.
Object need to be passed as shared_ptr (it also solve the problem of ownership and deletion). It works well, however, it segfaults when using as static libraries.
Then, I have a simple module Battery, compiled as shared object and links to the common library.
For the scope of the example, it does not contains much functions, but it actually use the LuaeClass:
// Battery.cpp
#include <lua.hpp>
#include "Common.h"
class Battery {
public:
int getPercent() {
return 100;
}
};
extern "C" int luaopen_battery(lua_State *L)
{
LuaeClass::createConverter<Battery, Battery>("Battery", "Battery");
return 0;
}
This compiled as a shared object named battery.so, Lua will use dlopen() and dlcose() to load it.
Finally, the main. It links to common also and use it to create objects.
// main.cpp
#include <iostream>
#include <memory>
#include <string>
#include <lua.hpp>
#include "Common.h"
using namespace std;
class LuaDeleter {
public:
void operator()(lua_State *L) {
lua_close(L);
}
};
typedef unique_ptr<lua_State, LuaDeleter> LuaState;
int main(void)
{
LuaState L(luaL_newstate());
luaL_requiref(L.get(), "_G", luaopen_base, 1);
luaL_requiref(L.get(), "package", luaopen_package, 1);
// This will dlopen() and dlclose()
string code = "local battery = require \"battery\"";
LuaeClass::createConverter<int, int>("Int", "Int");
if (luaL_dostring(L.get(), code.c_str()) != LUA_OK) {
cerr << lua_tostring(L.get(), -1) << endl;
}
return 0;
}
To summary:
Common.cpp, Common.h are compiled as simple static library (libcommon.a)
Main.cpp, compiled and links to libcommon.a
Battery.cpp, compiled as a shared object and links to libcommon.a
The main segfaults at exit, the core file says it's in the destructor of std::function<> so I guess it is called multiple times on the same pointer, is it?
Is the static library data shared in all code? How can I avoid this issue?
The begin of the core
#0 0x0000000000404062 in std::__1::function<void (void*, void*)>::~function() ()
#1 0x0000000000404025 in std::__1::function<void (void*, void*)>::~function() ()
The next trace are just unreadable and unusable.
The code and global/static data of static library will be injected into each module which links it. So for your case, there are multiple LuaeClass::converters instances exist in your project. And you need to call luaopen_battery() in each module which links the static library.
I am not sure if your crash has anything to do with static link, but I am quite sure you went to a complicated implementation.
The first issue you want to address is safely converting void* to A*, B*, C*. Which class/interface you want to export to Lua? If it's class C, you can define below methods in class C:
void pushThis(lua_State *L);
static C* getThis(lua_State *L, int idx);
Both methods use C*, so you don't need a convert function. You can use meta table to distinguish your pointers from other userdata. If you need B*, just:
B* b = (B*)C::getThis(L, idx);
And you may not really need a shared_ptr. shared_ptr doesn't help on deleting your C++ object when your Lua object is collected by GC(because the shared_ptr still exist in heap). Instead, you have to implement a __gc callback in the meta table to delete your object.
My main program would load a simple dynamic library called hello.so
In main
void* handle = dlopen("./hello.so", RTLD_LAZY);
In main , pass a callback function called testing (defined somewhere in main.h) and invoke the hello() from the dynamic library
typedef void (*callback)();
typedef void (*hello_t)( callback);
/* do something */
hello_t hello = (hello_t) dlsym(handle, "hello");
hello(testing);
In dynamic library,
#include
#include "main.h"
extern "C" void hello( void (*fn)() ) {
/*do something and then invoke callback function from main */ fn();
}
Are there other ways to allow functions/data of main to be called/used from dynamic library apart from using callbacks?
No, this is the preferred way of doing it, in my opinion. Any other way that I can think of involves making the DLL aware of the objects in the program it's linked with, which is most likely bad practice.
Regarding data, just a reminder though you didn't ask, it's usually best practice to copy any data that needs to be stored, if it's passed across library/program boundaries. You can get into a complete mess if you have the library using data whose lifetime is controlled by the program, and vice versa.