「QMLの基礎 - ライブラリ」の版間の差分

218行目: 218行目:
# 実行ファイル側のQMLファイルから動的ライブラリのオブジェクトのメソッドを呼び出して、動的ライブラリ内のQMLファイルを表示する。
# 実行ファイル側のQMLファイルから動的ライブラリのオブジェクトのメソッドを呼び出して、動的ライブラリ内のQMLファイルを表示する。
<br>
<br>
以下の構成を持つ2つのプロジェクトを作成したとする。<br>
上記セクションにある動的ライブラリの変更点のみを、以下に示す。<br>
* プロジェクト構成
** 動的ライブラリ
**: Utils
** 実行ファイル
**: Moc
<br>
<br>
まず、Utilsプロジェクトにおいて、関数のみを定義したUtils.cppファイルを作成する。<br>
まず、動的ライブラリのクラスおよびメソッドの変更点を記述する。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  // Utils_global.h
  // LibSample.h (動的ライブラリ側)
   
   
  #ifndef UTILS_GLOBAL_H
  #ifndef LIBSAMPLE_H
  #define UTILS_GLOBAL_H
  #define LIBSAMPLE_H
   
   
  #include <QtCore/qglobal.h>
  #include <QObject>
#include <QString>
#include <QQmlComponent>
#include <QtQml/qqmlengine.h>
#include "LibSample_global.h"
   
   
  #if defined(Q_OS_WIN)  // Windows
  class LIBSAMPLE_EXPORT LibSample : public QObject
    #if defined(UTILS_LIBRARY)
  {
      #define UTILS_EXPORT __declspec(dllexport)
     Q_OBJECT
    #else
      #define UTILS_EXPORT
    #endif
  #elif defined(Q_OS_LINUX)  // Linux
     #if defined(UTILS_LIBRARY)
      #define UTILS_EXPORT Q_DECL_EXPORT
    #else
      #define UTILS_EXPORT Q_DECL_IMPORT
    #endif
#endif
   
   
  #endif // UTILS_GLOBAL_H
public:
    explicit LibSample(QQmlEngine *engine, QObject *parent = nullptr);
    Q_INVOKABLE void showQmlWindow();
private:
    QQmlEngine *m_engine;
};
extern "C" {
    LibSample* createLibSample();
    void destroyLibSample(LibSample *instance);
}
  #endif // LIBSAMPLE_H
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  // Utils.cpp
  // LibSample.cpp (動的ライブラリ側)
   
   
  #include "Utils_global.h"
#include <QQmlComponent>
  #include <iostream>
#include <QtQuick/QQuickWindow>
  #include "LibSample.h"
 
LibSample::LibSample(QQmlEngine *engine, QObject *parent) : QObject(parent), m_engine(engine)
  {
    qDebug() << "LibSample lib";
}
   
   
  extern "C" UTILS_EXPORT void SampleHello(int count)
  void LibSample::showQmlWindow()
  {
  {
     while(--count)
     QQmlComponent component(m_engine, "qrc:/Hoge/Hoge.qml");
     {
       fprintf(stdout, "Hello!!");
    QObject *object = component.create();
     if (object) {
       QQuickWindow *window = qobject_cast<QQuickWindow*>(object);
      if (window) {
          window->show();
      }
     }
     }
}
LibSample* createLibSample()
{
    return new LibSample();
}
void destroyLibSample(LibSample *instance)
{
    delete instance;
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
次に、Mocプロジェクト(動的ライブラリを使用する側)から、動的ライブラリの関数を呼び出す。<br>
次に、実行ファイル側 (動的ライブラリを使用する側) から動的ライブラリを読み込み、動的ライブラリのクラスのインスタンスを生成する。<br>
生成したインスタンスをQMLコンテキストにセットして、QMLファイルから動的ライブラリのクラスのメソッドを呼び出す。<br>
<br>
<br>
<code>QLibrary</code>クラスから呼び出す関数は、必ず、C言語のグローバル関数として定義すること。<br>
<code>QLibrary</code>クラスから呼び出す関数は、必ず、C言語のグローバル関数として定義すること。<br>
272行目: 296行目:
<br>
<br>
<u>※注意</u><br>
<u>※注意</u><br>
<u>Windowsでは、動的ライブラリから関数を呼び出すには、<code>__declspec(dllexport)</code>を関数の前に付加すること。</u><br>
<u>Windowsでは、動的ライブラリからメソッドを呼び出すには、<code>__declspec(dllexport)</code>を関数の前に付加すること。</u><br>
<br>
<br>
<code>QLibrary</code>クラスのコンストラクタには、<code>.so</code>拡張子または<code>.dll</code>拡張子を付加しないライブラリ名を渡す。<br>
<code>QLibrary</code>クラスのコンストラクタには、<code>.so</code>拡張子または<code>.dll</code>拡張子を付加しないライブラリ名を渡す。<br>
動的ライブラリをリンクするには、<code>load</code>メソッドを実行する。<br>
動的ライブラリをリンクするには、<code>load</code>メソッドを実行する。<br>
<br>
次に、<code>resolve</code>メソッドを使用して呼び出す関数名を渡して、関数が存在する場合は関数ポインタが返る。<br>
次に、<code>resolve</code>メソッドを使用して呼び出す関数名を渡して、関数が存在する場合は関数ポインタが返る。<br>
関数名や型が間違っている場合は、0が返る。<br>
メソッド名や型が間違っている場合は、<code>0</code>が返る。<br>
<br>
<br>
もし、関数内でグローバル変数の値が変更された場合、次の関数を呼び出した時でも、グローバル変数の値を保持し続ける。<br>
もし、メソッド内でグローバル変数の値が変更された場合、次の関数を呼び出した時でも、グローバル変数の値を保持し続ける。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  // main.cpp
  // main.cpp (実行ファイル側)
   
   
  #include <QApplication>
  #include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
  #include <QLibrary>
  #include <QLibrary>
 
#include "LibSample.h"
  using SampleFunc = void (*)(int);
using CreateLibSampleInstance = LibSample* (*)();
  using DestroyLibSampleInstance = void (*)(LibSample*);
   
   
  int main(int argc, char * argv[])
  int main(int argc, char *argv[])
  {
  {
     QApplication a(argc, argv);
     QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    const QUrl url(u"qrc:/main.qml"_qs);
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app,
                    [url](QObject *obj, const QUrl &objUrl) {
                        if (!obj && url == objUrl)
                          QCoreApplication::exit(-1);
                    }, Qt::QueuedConnection);
    engine.load(url);
   
   
    // 動的ライブラリをリンクする
     QLibrary lib("LibSample");
     QLibrary lib("Utils");
     if (lib.load()) {
     lib.load();
      CreateLibSampleInstance createInstance = (CreateLibSampleInstance) lib.resolve("createLibSample");
      DestroyLibSampleInstance destroyInstance = (DestroyLibSampleInstance) lib.resolve("destroyLibSample");
   
   
    // 動的ライブラリの関数を取得する
      if (createInstance && destroyInstance) {
    SampleFunc Func = (SampleFunc)lib.resolve("SampleHello");
          LibSample *sample = createInstance();
          engine.rootContext()->setContextProperty("libSample", sample);
   
   
    if(Func != 0)
          QObject::connect(&app, &QCoreApplication::aboutToQuit, [sample, destroyInstance]() {
     {
            destroyInstance(sample);
       Func(10);
          });
        }
        else {
          qWarning() << "インスタンスメソッドの作成 / 破棄の解決に失敗";
        }
    }
     else {
       qWarning() << "動的ライブラリの読み込みに失敗";
     }
     }
   
   
     return a.exec();
     return app.exec();
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>