Calling main program functions from a dynamically loaded library (QPluginLoader) - c++

I am loading plugins (DLLs) dynamically at runtime using the Qt QPluginLoader class.
So far, I have successfully loaded plugins with functions that are called from the main program. Now, the plugins will need to call other functions in the main program. I've included the relevant header files in the plugin project, and it compiles without errors.
When I try to call the following plugin function from the main program:
// main program calling a function in a dll that has been dynamically
// loaded into the program:
PluginInterface* plugin = qobject_cast<PluginInterface*>(QPluginLoader(path)).instance();
plugin->DoSomething(); // works, writes a message to the console
plugin->callMainProgramFunction(); // not working
'
// test method in the plugin project (dll) that writes to console:
void TestDLL::DoSomething();
{
std::cout << "Hello, this messages comes from TestDLL! Have a nice day"; // works
}
'
// test method in the plugin project (dll) that tries to
// call a method in the main program:
void TestDLL::callMainProgramFunction()
{
Angle test; // angle.h is included, and offers geometric functions
std::cout << test.sine() << "\n"; // does not work, program stops
}
the program stops. I believe this is because the plugin does not know where to find the symbols (the code from angle.cpp that is linked and compiled into the main program), since it is linked into the program dynamically afterwards.
Many plugins will use the same functions, therefore I consider compiling each plugin with all the implementations a bad idea.
Is there a solution to this, using QPluginLoader? How can I tell the dynamically loaded plugins where to find symbols in the main program? I know that QLibrary offers a more manual way of exporting/importing functions and "resolve symbols", but lacks the neat instance functionality of QPluginLoader.

You can create a dll with common functions that are shared between the plugin and the main program, and link it in both the main program and the plugin.

QPluginLoader solves the problem that I described: Libraries that are loaded dynamically into the main program through QPluginLoader, will be able to call functions in the main program.
The cause to my problem was a subtle error in the plugin interface that I use.

It is possible, but don't forget on Linux to link the main program with the -rdynamic flag, so that symbols of the main program are visible from plugins.

Related

Calling C DLL from C++ gives Access Violation but C# project with DllImport working

I have a 32-bit 3rd party C DLL that I need to integrate with, but am hitting an error that's difficult to understand/track down.
I can compile and successfully link a simple C++ 32-bit app consisting of the following:
#include "stdafx.h"
#include <windows.h>
extern "C" int __stdcall external_method(int cardno);
int main()
{
int n = external_method(0);
return 0;
}
When I try to run the app though in debug mode it gives the following:
Unhandled exception at 0x100AADF5 (ExternalModule.dll) in
ConsoleApplication2.exe: 0xC0000005: Access violation reading location 0x00000000.
However, if I create a simple C# application that uses DllImport/PInvoke to call the same function it runs fine:
namespace ConsoleApplication3
{
class Program
{
[DllImport("ExternalModule.dll")]
public static extern int external_method(int n);
static void Main(string[] args)
{
external_method(0);
Debug.WriteLine("YES!");
}
}
}
I'm struggling to understand how one can work and the other fail. Unfortunately I have no access to the developer of the C DLL.
Any help much appreciated.
Update Thanks for the comments. Here is the header file entry for the method:
int __stdcall exernal_method(int cardno);
Am reasonably sure that the calling convention is ok. The DLL is being loaded because using the debug version of the DLL I can see it output some messages to the debug output before it fails.
Could it be an issue with stack being corrupted on exit of the method? I tried a couple of different calling conventions but this is the only one that the linker was able to work with.
Stack corruption is unlikely.
One possible reason is different DLL loading method. Your C++ app loads it statically (Windows loads your DLL before the process launched), C# dynamically (CLR loads the DLL after the process started to run). To test this hypothesis, remove ExternalModule.lib from linker, change your C++ code to call LoadLibrary and GetProcAddress instead.
Another possible reason is C# runtime initializes COM, C++ app doesn’t, and your DLL tried to use COM. In your C++ app, try to add CoInitialize[Ex] before your exernal_method.

Accessing static members of a class from dll

I have application written in C++ that uses SWIG for python integration.
Now under linux/osx when i build swig wrapper it creates so file that is used from application like this.
Py_Initialize();
PyRun_SimpleString("import MoBridge");
PyRun_SimpleString("a = MoBridge.MoBridge()");
PyRun_SimpleString("a.CreateQuadMesh()");
Py_Finalize();
What this does is it imports wrapper MoBridge, then it calls trough wrapper C++ function CreateQuadMesh(). Wrapper roughly looks roughly like this
h file:
#include "MoEngine.h"
class MoBridge
{
public:
MoBridge();
~MoBridge();
void CreateQuadMesh();
};
cpp file:
#include "mobridge.h"
void MoBridge::CreateQuadMesh()
{
MoEngine::CreateMesh();
}
The wrapper calls MoEngine static function and it in turn does what it does.
Now this works great under Linux/osx if I understood it correctly because the way so file is linked.
But under windows I had to create DLL and as far as I found DLL files are loaded differently so they live in different memory from the rest of the application and hence cannot see applications other static methods.
I know that I can use dllexport to expose methods from dll to the rest of the application. But in this case I'm looking on how to allow dll to access rest of the applications static functions in applications memory.
I would appreciate any point in the right direction.
If anyone gets stuck with this I have found solution that will resolve this in both linux, osx and windows.
using shared object *.so will of course work with linux/osx but luckily there is even easier solution to use with SWIG that is really not documented in SWIG but it's documented in python documentation (thank you python!)
For this to work you don't need to create dll or so file from your wrapper but after swig creates your *_wrap.cxx file you should include it in your project and before calling Py_Initialize() you import your module like this.
PyImport_AppendInittab("_MoBridge", PyInit__MoBridge);
Then you can use as previously mentioned:
Py_Initialize();
PyRun_SimpleString("import MoBridge");
PyRun_SimpleString("a = MoBridge.MoBridge()");
PyRun_SimpleString("a.CreateQuadMesh()");
Py_Finalize();
And basically since you have your *_wrap.cxx in your project and python is essentially living within your application since you initialised it you have exactly same behaviour like if you have used so in linux/osx except this work on all three platforms.
Cheers!

The procedure entry point __gxx_personality_v0 could not be located in the dynamic link library libstdc++-6.dll

I got that error when trying to run my opencv application. I´m using Windows7,CodeBlocks 12.11, opencv2.4.4 and MinGW compiler (the one that comes in CodeBlocks). It compiles and creates the executable but when i try to run it crashes with the procedure entry point error.
I have added C:\programs\CodeBlocks\Mingw\bin to "PATH" variable and i know there is libstdc++-6.dll.
I don´t know what´s hapenning.
This is the simple code:
include <iostream>
include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
cout << "Hello world!" << endl;
namedWindow("window");
Mat image=imread("mustang.jpg",CV_LOAD_IMAGE_COLOR);
imshow("window",image);
waitKey(0);
return 0;
}
The libstdc++-6.dll contains the runtime environment. It is an implementation of fundamental routines, such as the heap manager or the exception handling.
These fundamental routines are used in nearly every program. Thus, it would be a waste of memory to put a copy of them into every program. That is why they are usually packed into a shared library (DLL). The programs can then request the DLL when they need the routines of the runtime.
In your case, the libstdc++-6.dll contains a wrong version of the runtime. There are two possibilities:
Find a libstdc++-6.dll that contains the correct version of the runtime and copy it into the directory of your executable. You can determine whether a DLL is the correct one by running nm libstdc++-6.dll | grep personality. If the __gxx_personality_v0 shows up in the list, then you probably have the correct DLL.
Put a copy of the runtime environment into the executable. You can do this by adding -static-libgcc -static-libstdc++ to your linker parameters.
This question seems to have been answered several times here on stackoverflow.
What is __gxx_personality_v0 for? as one of them

LoadLibrary fails with error 203: The system could not find the environment option that was entered

I created a c# class library. I want to load this .dll in my win32 console application, because I have exported one function from the c# class library to unmanaged code and I don't know of any other way to call that function now.
But LoadLibraryA is giving me that error, what can it mean? Googling didn't help me at all.
Used this to export the function to unmanaged:
https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports#TOC-C-:
EDIT: Here is the code, sorry I didn't include it at first because it's as barebones as it gets:
using System;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
namespace ManagedLibrary
{
public class Test
{
[DllExport(CallingConvention = CallingConvention.Cdecl)]
public static void test()
{
Console.WriteLine("HI");
}
}
}
Looks like the unmanaged exports nuget tool doesn't work for me, the .dll loading errors were mostly obscure and unrelated as it seems (although I did switch to my home computer now)
After I have manually added the exports IL statement as described here:How do you export a method in a CIL DLL so that a native program can call it? I was able to call the C# code just fine.

[windows] back linking

There is shared class. Declarator is in shared header, implementation is in main program. Main program load DLL and exec some function from it, function create object of shared class.
Test code:
shared_header.h:
#include<stdio.h>
class sharedClass{
public:
sharedClass();
};
plugin.cpp -> libplugin.dll
#include"shared_header.h"
extern "C"
void loader(){
printf("Plugin is loaded!\n");
new sharedClass;
}
base.cpp -> base.exe
#include"shared_header.h"
sharedClass::sharedClass(){
printf("Shared class is loaded!\n");
}
int main(){
/*
some actions to load libplugin.dll and exec function loader
*/
return 0;}
So, I want see
Plugin is loaded!
Shared class is loaded!
And it works on Linux. But while I link libplugin.dll on Windows I have error "undefined refernce to sharedClass::sharedClass()". How I need link program and plugin to use this way?
PS. Mingw, stable version.
PPS. I'm so sorry for my terrible English.
Windows DLLs are non exactly the same thing as UNIX/Linux shared objects.
On Windows, DLLs must be fully linked and have all their references defined. Therefore, as your file plugin.cpp references the sharedClass constructor, the linker will require that this constructor is defined and available to create the DLL. It is not possible to provide it in the executable that loads the DLL.
On UNIX/Linux, shared objects behave differently. Their dependencies are solved when they are loaded by the executable. Therefore, the executable can provide some of the functions needed by the shared object.