C++ DLLs as plugins in Qt
-
What I look for is implementing into a Qt app, a plugin system. The plugin would be a DLL that accepts an array and returns some values (similarity metrics, where each DLL is a different metric)
I know that Qt has a plugin interface, but ideally I would like the plugins to be creatable without the framework itself.What I have so far is a working C++ code that does exactly that
void load() { WIN32_FIND_DATA fileData; HANDLE fileHandle = FindFirstFile(R"(.\plugins\*.dll)", &fileData); if (fileHandle == (void*)ERROR_INVALID_HANDLE || fileHandle == (void*)ERROR_FILE_NOT_FOUND) { return; } do { HINSTANCE temp = LoadLibrary((R"(.\plugins\)" + std::string(fileData.cFileName)).c_str()); if (!temp) { // error //std::cerr << "Couldn't load: " << fileData.cFileName << "!\n"; continue; } typedef std::unique_ptr<Base>(__cdecl* ObjProc)(void); typedef std::string(__cdecl* NameProc)(void); ObjProc objFunc = (ObjProc)GetProcAddress(temp, "getObj"); NameProc nameFunc = (NameProc)GetProcAddress(temp, "getName"); std::unique_ptr<Base> obj = objFunc(); std::cout << "\t" << obj->calc(5) << std::endl; } while (FindNextFile(fileHandle, &fileData)); }
I tried translating it as follows:
void ImageMetrics::loadPlugins() { qDebug ("PLUGIN1") ; WIN32_FIND_DATA fileData; HANDLE fileHandle = FindFirstFile(L"(.\plugins\*.dll)", &fileData); if (fileHandle == (void*)ERROR_INVALID_HANDLE || fileHandle == (void*)ERROR_FILE_NOT_FOUND) { return; } static int counter = 0; qDebug ("PLUGIN2") ; do { HINSTANCE temp = LoadLibrary( std::wstring(L"(.\plugins\)" + std::wstring(fileData.cFileName)).c_str()); std::string test = ws2s(std::wstring(L"(.\plugins\)" + std::wstring(fileData.cFileName)).c_str()); auto test1 =QString::fromStdString(test); qDebug() << test1; qDebug() << counter++; if (!temp) { qDebug("Couldn't load: !\n"); continue; } modules.push_back(temp); typedef std::unique_ptr<Base>(__cdecl* ObjProc)(void); typedef std::string(__cdecl* NameProc)(void); ObjProc objFunc = (ObjProc)GetProcAddress(temp, "getObj"); NameProc nameFunc = (NameProc)GetProcAddress(temp, "getName"); qDebug ("PLUGIN3") ; std::unique_ptr<Base> obj = objFunc(); m_Plugins.emplace_back(std::move(obj)); } while (FindNextFile(fileHandle, &fileData)); }
I tried pasting a Plugin folder with DLLs in different spaces, but cant get the software to read the data. I'm a complete newbie with Qt. Any help appreciated.
-
Okay, got a working (WINDOWS) solution, probably not perfect but oh well.
.h file
typedef double(*CalcFunction)(double); std::vector<CalcFunction> m_Plugins; void loadPlugins();
.cpp file
void ImageMetrics::loadPlugins() { m_Plugins.clear(); QDir directory(QDir::currentPath()); directory.cd(QString("Plugins")); auto path = QDir::cleanPath(directory.path()); SetDllDirectoryA(path.toStdString().c_str()); QStringList plugins = directory.entryList(QStringList() << "*.dll", QDir::Files); foreach(QString plugin, plugins) { QLibrary lib(plugin); CalcFunction calc = (CalcFunction)lib.resolve("calc"); if (calc){ m_Plugins.push_back(calc); qDebug() << m_Plugins.back()(25); } else qDebug() << lib.errorString(); } }
PSA if other get stuck and find their way here:
- Make sure your DLLs match your Qt Creator architecture (I was using 32 bit DLLs with 64 bit Creator.
- Your DLL functions have to be wrapped in
extern "C" __declspec(dllexport)
(I didn't have the extern part)
-
Hi and welcome to devnet,
Qt already provides all you need to implement plugins for your application in a cross platform fashion.
-
-
If I may, you want to add plugins to a Qt application but not use Qt's facilities to do that which is a bit counter-productive.
What I would recommend is to implement the core functionalities that you want in "pure c++" in a library and then use that library to build a plugin that you can use with QPluginLoader. That way you can keep the two things separated while taking advantage of the system.
As for your location issue, where exactly did you put your plugin folder ?
-
Yea, ideally I would use plugin loader, but it's not optimal, as it forces (afaik) people that would wish to write more DLLs to get the framework.
As for your suggestion, if that allows people to write plugins without compiling Qt specific code -> could you point me, where I could read up on such a procedure? This is all very new territory to me.
Lastly about the folder; I just copy pasted the folder in the main app directory, app/build directory, app/build/debug directory
-
Okay, got a working (WINDOWS) solution, probably not perfect but oh well.
.h file
typedef double(*CalcFunction)(double); std::vector<CalcFunction> m_Plugins; void loadPlugins();
.cpp file
void ImageMetrics::loadPlugins() { m_Plugins.clear(); QDir directory(QDir::currentPath()); directory.cd(QString("Plugins")); auto path = QDir::cleanPath(directory.path()); SetDllDirectoryA(path.toStdString().c_str()); QStringList plugins = directory.entryList(QStringList() << "*.dll", QDir::Files); foreach(QString plugin, plugins) { QLibrary lib(plugin); CalcFunction calc = (CalcFunction)lib.resolve("calc"); if (calc){ m_Plugins.push_back(calc); qDebug() << m_Plugins.back()(25); } else qDebug() << lib.errorString(); } }
PSA if other get stuck and find their way here:
- Make sure your DLLs match your Qt Creator architecture (I was using 32 bit DLLs with 64 bit Creator.
- Your DLL functions have to be wrapped in
extern "C" __declspec(dllexport)
(I didn't have the extern part)