如何使用QPluginLoader在Qt中创建同一插件的多个实例?

如何使用QPluginLoader在Qt中创建同一插件的多个实例?,qt,multiple-instances,Qt,Multiple Instances,首先,我为我的英语感到抱歉 我已经开发了使用Qt的财政打印机驱动程序。驱动程序规范是PC和设备之间通过RS232进行的通信。驱动程序存储在共享对象(Qt插件)中,服务器通过QPluginLoader执行其加载 所以,关于我的问题。。。当我使用一个设备和一个驱动程序实例时,所有这些都可以正常工作,但当我连接多个设备(例如3个)时,只有最后加载的设备才能工作。我做了许多代码检查,读取了许多日志数据转储,设备和端口命名没有错误,但是如果我使用命令寻址第一个设备-2个左设备接收相同的命令(根据日志条目)

首先,我为我的英语感到抱歉

我已经开发了使用Qt的财政打印机驱动程序。驱动程序规范是PC和设备之间通过RS232进行的通信。驱动程序存储在共享对象(Qt插件)中,服务器通过QPluginLoader执行其加载

所以,关于我的问题。。。当我使用一个设备和一个驱动程序实例时,所有这些都可以正常工作,但当我连接多个设备(例如3个)时,只有最后加载的设备才能工作。我做了许多代码检查,读取了许多日志数据转储,设备和端口命名没有错误,但是如果我使用命令寻址第一个设备-2个左设备接收相同的命令(根据日志条目),并且只有最后加载的设备执行命令

例如:我从服务器向设备1发送PrintReceive命令,在设备1的日志文件中我看到条目:PrintReceive,在设备2的日志文件中我看到条目:PrintReceive,:PrintReceive,在设备3的日志文件中我看到3个相同的条目。所以,正如我看到的问题一样-QPluginLoader为第一个加载的设备创建了一个驱动程序实例,然后,当我尝试将驱动程序加载到第二个设备时-QPluginLoader为每个设备创建了新实例,并用最近创建的实例替换第一个设备的驱动程序,依此类推。所以,至少,对于许多设备,我只有一个驱动程序(插件)实例,我的应用程序逻辑崩溃

我的问题是:如何使用QPluginLoader在Qt中创建同一插件的多个实例?我的驱动程序界面和下面列出的加载代码

class IPrinterDriver : public QObject
{
public:

// Printer driver initialization
virtual bool Init(QextSerialPort* port, const QString& deviceID) = 0;

// Driver identify name
virtual QString GetName() = 0;

// Gets current device state
virtual DeviceStates GetState() = 0;

// Gets device info and state test
virtual QString DeviceInfo() = 0;

// Set print mode to specified
virtual bool SetPrintMode(PrintModes mode) = 0;

// Get current print mode
virtual PrintModes PrintMode() const = 0;

// Sets device password from configuration
virtual void SetDevicePasswords(int operatorPassword, int adminPassword) = 0;

// Sets non-fiscal permissoin to device
virtual void SetNonFiscalModePermission(bool allowed) = 0;

// Gets device operator password
virtual int GetOperatorPassword() const = 0;

// Gets device administrator password
virtual int GetAdministratorPassword() const = 0;

// Gets non-fiscal mode permission
virtual bool GetNonFiscalModePermission() const = 0;

// Payment transaction
virtual bool PaymentTransaction(PaymentItem& item) = 0;

// Query device for X-Report
virtual bool GetXReport() = 0;

// Encashment transaction (Z-Report)
virtual bool Encash(bool fromBuffer) = 0;

// Print transaction
virtual bool Print(QString& text) = 0;

// Performs fiscal sale at device and returns receipt data
virtual FiscalReceiptData FPSSale(int requestID, int amount) = 0;

// Gets last fiscal receipt data
virtual FiscalReceiptData GetLastReceiptData() = 0;

// Gets serial port assigned to device
virtual QextSerialPort* GetDevicePort() = 0;

signals:

// Emits when device logging needed
virtual void DeviceLoggingNeeded(LogEntry entry, const QString& deviceID) = 0;

};

Q_DECLARE_INTERFACE(IPrinterDriver, "InfSys.Devices.IPrinterDriver/1.0")
和驾驶员装载方法:

// Performs loading specified driver for device at specified port
IPrinterDriver* PrintSystem::LoadDriver(PortConfiguration portConfig, const QString&   driverName, const QString& adminPassword, const QString& operPassword, const QString& deviceID)
{
IPrinterDriver* result = NULL;

// Prepare plugin loader
QDir driversDir(_driversPath);
QStringList filesMask;
filesMask << tr("libdriver.%1.*").arg(driverName);
driversDir.setNameFilters(filesMask);
QStringList driversFiles = driversDir.entryList(QDir::Files);

// Load plugin with specified driver
foreach(QString driverFile, driversFiles)
{
    // Load current driver;
    QString driverFileName = driversDir.absoluteFilePath(driverFile);
    QPluginLoader driversLoader(driverFileName);

    // Try to init driver
    QObject *driverObject = driversLoader.instance();
    if (driverObject)
    {
        result = qobject_cast<IPrinterDriver *>(driverObject);
        if (result && (result->GetName() == driverName))
        {
            QextSerialPort* devicePort = ConfigureSerialPort(portConfig);
            if (devicePort == NULL)
            {
                driversLoader.unload();
                return NULL;
            }

            // Init device
            result->SetDevicePasswords(operPassword.toInt(), adminPassword.toInt());
            result->SetNonFiscalModePermission(false);
            result->SetPrintMode(Fiscal);
            connect(result, SIGNAL(DeviceLoggingNeeded(LogEntry,QString)), App->LoggingModule, SLOT(OnDeviceLoggingNeeded(LogEntry,QString)), Qt::QueuedConnection);
            bool initResult = result->Init(devicePort, deviceID);
            if (!initResult)
            {
                driversLoader.unload();
                return NULL;
            }
        }
        else
            driversLoader.unload();
    }
}

return result;
}
//在指定端口为设备加载指定的驱动程序
IPrinterDriver*打印系统::LoadDriver(端口配置portConfig、常量QString和driverName、常量QString和adminPassword、常量QString和operPassword、常量QString和设备ID)
{
IPrinterDriver*结果=NULL;
//准备插件加载程序
QDir driversDir(_driversPath);
QStringList文件掩码;
filesMask GetName()==driverName))
{
QextSerialPort*devicePort=ConfigureSerialPort(portConfig);
如果(devicePort==NULL)
{
driversLoader.unload();
返回NULL;
}
//初始化设备
结果->设置设备密码(operPassword.toInt(),adminPassword.toInt());
结果->设置非DiscalModePermission(false);
结果->设置打印模式(财政);
连接(结果、信号(DeviceLoggingNeeded(LogEntry,QString))、应用程序->日志模块、插槽(OnDeviceLoggingNeeded(LogEntry,QString))、Qt::QueuedConnection;
bool initResult=result->Init(devicePort,deviceID);
如果(!initResult)
{
driversLoader.unload();
返回NULL;
}
}
其他的
driversLoader.unload();
}
}
返回结果;
}

我在自己的项目中研究这个问题已经有一段时间了。我相信没有任何方法可以直接做到这一点——QPluginLoader正在按设计工作

到目前为止,我提出的解决这个问题的最直接的方法是使主插件接口函数成为您实际需要的对象的工厂

在下面的示例中,我实际需要的是多个IPlaybackDataSource对象。所以我创建了一个插件实现的工厂接口。然后插件返回我想要的任意多个类型的对象

IPlaybackDataSource.h:

#include <QSharedPointer>

class IPlaybackDataSource {
public:
    virtual bool open()=0;
};

// This is the interface that the plugin will implement
class IPlaybackDSFactory {
public:
    virtual QSharedPointer<IPlaybackDataSource> newDataSource()=0;
};

Q_DECLARE_INTERFACE(IPlaybackDSFactory,
                     "com.moberg.DeviceSimulators.IPlaybackDSFactory/1.0")
#包括
类IPlaybackDataSource{
公众:
虚拟bool open()=0;
};
//这是插件将实现的接口
类IPlaybackDSFactory{
公众:
虚拟QSharedPointer newDataSource()=0;
};
Q_DECLARE_接口(IPlaybackDSFactory,
“com.moberg.DeviceSimulators.IPlaybackDSFactory/1.0”)
TranFile.h:

#include <QtGui>
#include "TranFile_global.h"
#include "IPlaybackDataSource.h"


class TRANFILESHARED_EXPORT TranFile : public QObject, public IPlaybackDSFactory
{
    Q_OBJECT
    Q_INTERFACES(IPlaybackDSFactory)

public:
    TranFile();
    ~TranFile();

    virtual QSharedPointer<IPlaybackDataSource> newDataSource();
};
#包括
#包括“TranFile_global.h”
#包括“IPlaybackDataSource.h”
类TRANFILESHARED_导出TranFile:public QObject,public IPlaybackdFactory
{
Q_对象
Q_接口(IPlaybackDSFactory)
公众:
TranFile();
~TranFile();
虚拟QSharedPointer newDataSource();
};
TranFile.cpp:

#include "TranFile.h"

Q_EXPORT_PLUGIN2(IPlaybackDSFactory, TranFile );

#include <QtCore>
#include <QDebug>

TranFile::TranFile(): QObject(), IPlaybackDSFactory() {}
TranFile::~TranFile() {}

QSharedPointer<IPlaybackDataSource> TranFile::newDataSource() {
    return QSharedPointer<IPlaybackDataSource>();
}
#包括“TranFile.h”
Q_EXPORT_PLUGIN2(IPlaybackDSFactory,TranFile);
#包括
#包括
TranFile::TranFile():QObject(),IPlaybackDSFactory(){}
TranFile::~TranFile(){}
QSharedPointer TranFile::newDataSource(){
返回QSharedPointer();
}