QPluginLoader.instance() - 它是如何工作的?

QPluginLoader.instance() - how does it really work?

我目前正在从事一个以动态插件加载为中心的 Qt 项目。我正在使用 Qt 的 QPluginLoader 加载 DLL。通过CameraPluginStructs访问不同的插件,定义如下:

struct CameraPluginStruct
{
    QString name;
    QString filePath;
    CameraPluginInterface* plugin;
    QPluginLoader* pluginLoader;

    CameraPluginStruct(QString filePath=nullptr, QString name=nullptr):
         filePath(filepath), name(name), plugin(nullptr), pluginLoader(nullptr){}
};

要加载插件,调用以下函数:

void loadPlugin(CameraPluginStruct& p)
{
    p.pluginLoader = new QPluginLoader(p.filePath);
    p.pluginLoader->load();

    QObject* possiblePlugin = p.pluginLoader->instance(); //QPluginLoader.instance();

   if(possiblePlugin) 
   {
       // cast from QObject to correct type:
       p.plugin = qobjectcast<CameraPluginInterface>(possiblePlugin);
   }
}

为了卸载插件,我使用了这个函数:

void unloadPlugin(CameraPluginStruct& p)
{
    p.pluginLoader->unload();  // QPluginLoader.unload(); 
    p.pluginLoader->~QPluginLoader();

    p.pluginLoader = nullptr;
    p.plugin = nullptr;
 }

我制作了一些简单的测试插件,可以在调用构造函数时将消息写入控制台。为简单起见,假设我有两个测试插件,DLL A 和 DLL B。当我使用 loadPlugin() 函数加载 A 时,插件中的构造函数被调用,并且相应的消息写入控制台。我可以用 B 做同样的事情,而且一切似乎都有效——B 的构造函数消息被写入控制台,其他函数似乎也能正常工作。

现在,当我尝试创建另一个连接到 A 或 B 的 CameraPluginStruct 时出现问题。没有消息写入控制台,这让我认为没有调用构造函数。尽管如此,我还是能够成功调用插件中的其他测试函数(DoSomething(),见下文)。如果我卸载连接到 A 或 B 的所有 CameraPlugins,然后再次加载 DLL,则在第一次加载时再次调用构造函数。

QPluginLoader.instance()调用在文档中描述如下:

"Returns the root component object of the plugin. (...) The component object is a QObject. Use qobject_cast() to access interfaces you are interested in." http://doc.qt.io/qt-5/qpluginloader.html#instance

DLL 中的构造函数每次都会被调用,而不仅仅是第一次,这不是很自然吗?

据我所知,对于任何程序,DLL 只加载一次。因此,我也尝试在每个 DLL 文件中只使用一个 QPluginLoader,结果相同。 Qt 还说:

"Multiple instances of QPluginLoader can be used to access the same physical plugin." http://doc.qt.io/qt-5/qpluginloader.html#details

因此我看不出这怎么会是问题的根源。

如果有人能阐明 QPluginLoader.instance() 的真正工作原理,我将不胜感激。为什么构造函数——至少看起来是这样——只在我第一次使用 instance() 调用时被调用?

谢谢!

这是在 DLL 中找到的代码(A 和 B 中的输出文本不同):

TestDLL::TestDLL()
{
    std::cout << "This is written from the constructor in A \n";
}

QString TestDLL::Name() const
{
    return "Hello, writing from Name() \n";
}

void TestDLL::DoSomething() const
{
   qDebug() << "Hello, this text comes from DoSomething()"\n;
}

加载插件时(即第一次调用 QPluginLoader::instance()),然后会创建一个 单个 实例 - 这是您的根实例。根实例是 QPluginLoader 将为您创建的唯一实例。

如果您想要更多,则可以为您的插件 class 创建一个 createInstance()clone() 方法,以便可以从根实例创建新实例。或者更传统的做法是,将你的插件 class 设为你希望公开的 class 类型的 factory