简体   繁体   中英

Accessing C++ class member functions of a DLL in Qt

I am able to create the instance of the class in Qt main.cpp but my application is crashing on trying to access class member function of the DLL.

How do I do it?

If this is my dll.h

 #ifndef DIVFIXTURE_H
 #define DIVFIXTURE_H

#include<QObject>
#include<QVariant>

class __declspec(dllexport) DivFixture : public QObject
{
    Q_OBJECT
public:
    Q_INVOKABLE DivFixture();
    Q_INVOKABLE void setNumerator(QVariant num);
    Q_INVOKABLE void setDenominator(QVariant denom);
    Q_INVOKABLE QVariant quotient();

private:
    double numerator, denominator;
};

#endif

This my dll.cpp

#include "testfixture.h"

DivFixture::DivFixture(){}

void DivFixture::setNumerator(QVariant num)
{
    numerator=num.toDouble();
}

void DivFixture::setDenominator(QVariant denom)
{
    denominator=denom.toDouble();
}

QVariant DivFixture::quotient()
{
    QVariant ret;
    ret=numerator/denominator;
    return ret;
}

//non-class function to return pointer to class
extern "C" __declspec(dllexport) DivFixture* create()
{
     return new DivFixture();
}

This is main.cpp of my Qt application where I'm importing the DLL library

QLibrary library(("C:\\somepath\\testFixture.dll");
if (!library.load())
    qDebug() << library.errorString() << endl;
if (library.load())
    qDebug() << "library loaded" << endl;
DivFixture  *r1=NULL;

typedef DivFixture* (*MyPrototype)();

auto myFunction = (MyPrototype)library.resolve("create");
qDebug()<<myFunction;
if (myFunction)
    r1=Function(); // able to create instance of DivFixture
    r1->quotient(); //I'm not able to access class member function

Why am I not able to access class member function quotient() using class instance? Program is crashing at this line r1->quotient(); . Instead of creating a prototype of the function in DLL like typedef DivFixture* (*MyPrototype)(); , can I create a prototype of my class DivFixture to access its member functions?

Note: It didn't compile for me at first (code provided is not complete), so I had to make some changes, hope I've preserved the functionality you're aiming to.

First, some comments about creating/using DLLs:

  1. __declspec(dllexport) is only necessary when you want to import symbols, as with create . As you are creating the object from within the DLL, the class itself doesn't have to be exported.
  2. If you define your class in the way you do, the compiler will wait for the definition too, which happens to be in a DLL (and that DLL is not providing a .lib with the definitions table). It means that the code won't compile.
  3. To fix that you can either:
    • you export the class too, the compiler generates a .lib file (at least in VS) and link your application with it, which means that all the QLibrary code is not necessary.
    • you convert your class in a pure virtual class (only public members are required here), derive it to an inner class of the DLL (the implementation class ) and use create as a factory (it creates an instance of the implementation class).

As you seem to aim to use the QLibrary , maybe to make a plugin-like feature, I'm showing you the second solution, if you prefer the other one, just let me know and I'll extend the answer to cover that.

Solution based on pure virtual class

dll.h, public header file, to expose the design of the class

#ifndef DIVFIXTURE_H
#define DIVFIXTURE_H

#include<QObject>
#include<QVariant>

class DivFixture : public QObject {
public:
  virtual ~DivFixture() {}
  virtual Q_INVOKABLE void setNumerator(QVariant num) = 0;
  virtual Q_INVOKABLE void setDenominator(QVariant denom) = 0;
  virtual Q_INVOKABLE QVariant quotient() = 0;
};

#endif

dll_impl.h, not intended to be used outside the DLL, stores the actual

#ifndef DIVFIXTURE_IMPL_H
#define DIVFIXTURE_IMPL_H

#include "dll.h"

class DivFixture_Impl : public DivFixture {
public:
  DivFixture_Impl();
  virtual ~DivFixture_Impl() {}

  virtual Q_INVOKABLE void setNumerator(QVariant num) override;
  virtual Q_INVOKABLE void setDenominator(QVariant denom) override;
  virtual Q_INVOKABLE QVariant quotient() override;

protected:
  double numerator, denominator;
};

#endif

dll.cpp, actual implementation

#include "dll_impl.h"

DivFixture_Impl::DivFixture_Impl() : numerator(0.0), denominator(1.0) {}

void DivFixture_Impl::setNumerator(QVariant num)
{
  numerator = num.toDouble();
}

void DivFixture_Impl::setDenominator(QVariant denom)
{
  denominator = denom.toDouble();
}    

QVariant DivFixture_Impl::quotient()
{
  QVariant ret;
  ret = numerator / denominator;
  return ret;
}

// non-class function to return pointer to class
extern "C" __declspec(dllexport) DivFixture* create()
{
  return new DivFixture_Impl();
}

main.cpp

#include <QtCore>
#include "../dll/dll.h"

int main()
{
  QLibrary library("dll.dll");
  if (!library.load()) {
    qDebug() << library.errorString();
    return 0;
  }

  qDebug() << "library loaded";

  typedef DivFixture * (*MyPrototype)();
  auto myFunction = (MyPrototype)library.resolve("create");
  qDebug() << myFunction;

  DivFixture* r1 = nullptr;
  if (myFunction)
    r1 = myFunction();

  if (r1 != nullptr) {
    r1->setDenominator(2.0);
    r1->setNumerator(10.0);
    auto r = r1->quotient();
    qDebug() << r.toDouble();
  } else {
    qDebug() << "r1 not created!";
  }

  return 0;
}

Additional notes

Regarding the crash, the third line in the code below will be executed regardless myFunction is null or not, so the crash may actually come from the fact that r1 is not initialized.

if (myFunction)
    r1=myFunction();
    r1->quotient();

Be careful about incongruences between indentation and actual code blocks. Use braces here:

if (myFunction) {
    r1=myFunction();
    r1->quotient();
}

or check that r1 is not null before using it:

if (myFunction)
    r1=myFunction();
if (r1 != nullptr)
    r1->quotient();

Also, probably it is just a typo but you check for if (myFunction) but in the next line call Function instead of myFunction . The same for the header file names. Be careful about these things when posting code, since they make very difficult to reproduce your problem, thus you probably won't get an answer or an adequate one.

Finally, and as a small note, unless you want to insert an additional blank line, qDebug already adds a line break at the end, so it is not necessary to use the endl .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM