Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. connect: External "C" function
Forum Updated to NodeBB v4.3 + New Features

connect: External "C" function

Scheduled Pinned Locked Moved Solved General and Desktop
16 Posts 4 Posters 1.8k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • F fem_dev

    Thank you @JKSH for your quick response...

    @JKSH said in connect: External "C" function:

    There are many ways you could implement the exporting function.

    I think that I need some help to understand in which scope should I write this lines...

    The problem is: Only inside the main application I can write something like this:

    Plugin *pluginInstance = nullptr; // This pointer can be updated when you construct your plugin object
    

    Because each plugin is loaded by the main application using QPluginLoader.
    So, I think that I can't use this line above inside the Plugin class. Am I right?

    Here is my plugin.h header file:

    #include "dialog.h"
    #include "plugin_global.h"
    #include "plugin_qt_api.h"
    
    // Fortran subroutines
    extern "C" {
        void callFortran(...input arguments ....);
        void fortranMsg(int msgType, char* msg);
    }
    
    class PLUGIN_EXPORT Plugin : public Plugin_API
    {
        Q_OBJECT
        Q_PLUGIN_METADATA(IID "com.rotortest.plugin")
        Q_INTERFACES(Plugin_API)
    
    private:
        Dialog _ui;
    
    public:
    
        explicit Plugin(QObject* parent = nullptr);
        ~Plugin();
    
        //... All Methods override
    
        void receiveMsg(int msgType, char* msg);
    };
    

    Here is my plugin.cpp implementation:

    #include <iostream>
    #include "plugin.h"
    #include "dialog.h"
    
    Plugin::Plugin(QObject* parent)
    {
    }
    
    Plugin::~Plugin()
    {
    }
    
    void Plugin::receivedMsg(int msgType, char* msg)
    {
    
    }
    
    void fortranMsg(int msgType, char* msg)
    {
        std::cout << msgType << " | " << msg << std::endl;
    
        // SEND DATA TO A PLUGIN METHOD
        // HOW?
    }
    

    Could you help me pass this data from the fortranMsg () function to the Plugin :: receivedMsg () method?

    A first thought that comes to mind is that I should try to make this connection entirely within the shared library (plugin) project, without resorting to the main application project.
    Or is there a better way to "connect" via the main application?

    jsulmJ Offline
    jsulmJ Offline
    jsulm
    Lifetime Qt Champion
    wrote on last edited by
    #4

    @fem_dev said in connect: External "C" function:

    // SEND DATA TO A PLUGIN METHOD
    // HOW?

    Like @JKSH suggested.
    Add a header file and put

    extern Plugin *pluginInstance;
    

    there. Then define pluginInstance in one of your cpp files (main.cpp for example). Include the header file in the cpp file where you define fortranMsg() and you can call pluginInstance as suggested.

    https://forum.qt.io/topic/113070/qt-code-of-conduct

    F 1 Reply Last reply
    1
    • jsulmJ jsulm

      @fem_dev said in connect: External "C" function:

      // SEND DATA TO A PLUGIN METHOD
      // HOW?

      Like @JKSH suggested.
      Add a header file and put

      extern Plugin *pluginInstance;
      

      there. Then define pluginInstance in one of your cpp files (main.cpp for example). Include the header file in the cpp file where you define fortranMsg() and you can call pluginInstance as suggested.

      F Offline
      F Offline
      fem_dev
      wrote on last edited by
      #5

      @jsulm Thank you...I'm almost there...

      Here is what I did:

      #include <iostream>
      #include "plugin.h"
      #include "dialog.h"
      
      extern Plugin *pluginInstance;
      
      Plugin::Plugin(QObject* parent)
      {
      }
      
      void Plugin::receivedMsg(int msgType, char* msg)
      {
      }
      
      void fortranMsg(int msgType, char* msg)
      {
          std::cout << msgType << " | " << msg << std::endl;
      
          if (pluginInstance)
               pluginInstance->receivedMsg(msgType, msg);
      }
      

      The shared library (plugin) compiles without any error or warning. All ok!

      But when my main application tries to load this shared library (using QPluginLoader) I got this run-time error:

      Cannot load library libLobular-Bearing.so: undefined symbol: pluginInstance
      

      What is missing? How can I fix it?

      Thank you,

      JonBJ 1 Reply Last reply
      0
      • F fem_dev

        @jsulm Thank you...I'm almost there...

        Here is what I did:

        #include <iostream>
        #include "plugin.h"
        #include "dialog.h"
        
        extern Plugin *pluginInstance;
        
        Plugin::Plugin(QObject* parent)
        {
        }
        
        void Plugin::receivedMsg(int msgType, char* msg)
        {
        }
        
        void fortranMsg(int msgType, char* msg)
        {
            std::cout << msgType << " | " << msg << std::endl;
        
            if (pluginInstance)
                 pluginInstance->receivedMsg(msgType, msg);
        }
        

        The shared library (plugin) compiles without any error or warning. All ok!

        But when my main application tries to load this shared library (using QPluginLoader) I got this run-time error:

        Cannot load library libLobular-Bearing.so: undefined symbol: pluginInstance
        

        What is missing? How can I fix it?

        Thank you,

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by JonB
        #6

        @fem_dev
        You are missing where @jsulm / @JKSH said:

        Then define pluginInstance in one of your cpp files (main.cpp for example)

        You need the line reading

        Plugin *pluginInstance = nullptr; // This pointer can be updated when you construct your plugin object
        

        in your main application. Once, in one of its .cpp files.. Note that is without the extern. Where do you have this?

        Explanation:

        Your shared library has extern Plugin *pluginInstance; in it. That means it says "there is/must be a pluginInstance out there, which I can use". That is what extern means. So it compiles.

        When you come to load at run-time, your program needs to have defined this pluginInstance, to provide this variable. Without it you get undefined symbol. The statement Plugin *pluginInstance, without the extern, defines the symbol. That is needed in some one (and only one) .cpp file of the main application loading your shared library.

        F 1 Reply Last reply
        3
        • JonBJ JonB

          @fem_dev
          You are missing where @jsulm / @JKSH said:

          Then define pluginInstance in one of your cpp files (main.cpp for example)

          You need the line reading

          Plugin *pluginInstance = nullptr; // This pointer can be updated when you construct your plugin object
          

          in your main application. Once, in one of its .cpp files.. Note that is without the extern. Where do you have this?

          Explanation:

          Your shared library has extern Plugin *pluginInstance; in it. That means it says "there is/must be a pluginInstance out there, which I can use". That is what extern means. So it compiles.

          When you come to load at run-time, your program needs to have defined this pluginInstance, to provide this variable. Without it you get undefined symbol. The statement Plugin *pluginInstance, without the extern, defines the symbol. That is needed in some one (and only one) .cpp file of the main application loading your shared library.

          F Offline
          F Offline
          fem_dev
          wrote on last edited by
          #7

          @JonB Almost there...

          My shared library (plugin) have a Interface Class called Plugin_API as you can see below:

          class PLUGIN_EXPORT Plugin : public Plugin_API
          {
              Q_OBJECT
              Q_PLUGIN_METADATA(IID "com.rotortest.plugin")
              Q_INTERFACES(Plugin_API)
          ...
          }
          

          So, inside my main application I have the same Plugin_API Interface...not the Plugin class.
          I think that the extern variable declaration must be PluginAPI type in both Qt projects (plugin and main application), right?

          #include <iostream>
          #include "plugin.h"
          #include "dialog.h"
          
          extern Plugin_API *pluginInstance; // Changed from 'Plugin' to 'Plugin_API'
          
          Plugin::Plugin(QObject* parent)
          {
          }
          
          void Plugin::receivedMsg(int msgType, char* msg)
          {
          }
          
          void fortranMsg(int msgType, char* msg)
          {
              std::cout << msgType << " | " << msg << std::endl;
          
              if (pluginInstance)
                   pluginInstance->receivedMsg(msgType, msg);
          }
          

          In my main application project, I opened the main GUI window Widget (called: App.cpp) and tried to add this line below:

          #include "app.h"
          #include "ui_app.h"
          
          Plugin_API *pluginInstance = nullptr;
          
          App::App(QWidget *parent)
              : QMainWindow(parent)
              , ui(new Ui::App)
          {
              ui->setupUi(this);
          ...
          }
          

          But I got the same run time error:

          libLobular-Bearing.so: undefined symbol: pluginInstance
          

          I tried to change the pointer value inside the App:loadPlugins() method (as you can see below) but without success too.

          void App::loadPlugins(const QStringList pluginsList)
          {
              foreach(QString file, pluginsList) {
          
                  QPluginLoader loader(file);
          
                  // Error checking:
                  if (!loader.load()) {
                      sendErrorMsg(tr("%1: ").arg(loader.errorString()));
                      continue;
                  }
          
                  // Get and display the plugin file name:
                  const QStringList pathSplited = loader.fileName().split("/");
                  const QString fileName = pathSplited.last();
                  sendStatusMsg(tr("Loading plugin: %1").arg(fileName));
          
                  // Cast plugin interface:
                  Plugin_API* plugin = qobject_cast<Plugin_API*>(loader.instance());
          
                  // Error chekcing: nullptr
                  if (!plugin) {
                      sendErrorMsg(tr("Wrong Plugin API! Could not cast: %1").arg(loader.fileName()));
                      continue;
                  }
          
                  // ===== CONNECT ALL SIGNALS /  SLOTS ===== //
                  bool conn1 = connect(plugin, &Plugin_API::sendMsg, this, &App::receivedMsg);
                  bool conn2 = connect(plugin, &Plugin_API::savePluginSettings, this, &App::receivedPluginSettings);
          
                  bool allConnections = conn1 & conn2;
          
                  if (!allConnections) {
                      sendErrorMsg(tr("Unable to connect: %1").arg(plugin->getName()));
                      continue;
                  }
          
                  pluginInstance = plugin; // TRY TO USE THE POINTER
          
                  // Store the plugin in a map:
                  _pluginsMapMap[plugin->getType()][plugin->getName()] = plugin;
              }
          }
          

          Could you please help me a little bit more?
          How can I fix it?

          jsulmJ JonBJ 2 Replies Last reply
          0
          • F fem_dev

            @JonB Almost there...

            My shared library (plugin) have a Interface Class called Plugin_API as you can see below:

            class PLUGIN_EXPORT Plugin : public Plugin_API
            {
                Q_OBJECT
                Q_PLUGIN_METADATA(IID "com.rotortest.plugin")
                Q_INTERFACES(Plugin_API)
            ...
            }
            

            So, inside my main application I have the same Plugin_API Interface...not the Plugin class.
            I think that the extern variable declaration must be PluginAPI type in both Qt projects (plugin and main application), right?

            #include <iostream>
            #include "plugin.h"
            #include "dialog.h"
            
            extern Plugin_API *pluginInstance; // Changed from 'Plugin' to 'Plugin_API'
            
            Plugin::Plugin(QObject* parent)
            {
            }
            
            void Plugin::receivedMsg(int msgType, char* msg)
            {
            }
            
            void fortranMsg(int msgType, char* msg)
            {
                std::cout << msgType << " | " << msg << std::endl;
            
                if (pluginInstance)
                     pluginInstance->receivedMsg(msgType, msg);
            }
            

            In my main application project, I opened the main GUI window Widget (called: App.cpp) and tried to add this line below:

            #include "app.h"
            #include "ui_app.h"
            
            Plugin_API *pluginInstance = nullptr;
            
            App::App(QWidget *parent)
                : QMainWindow(parent)
                , ui(new Ui::App)
            {
                ui->setupUi(this);
            ...
            }
            

            But I got the same run time error:

            libLobular-Bearing.so: undefined symbol: pluginInstance
            

            I tried to change the pointer value inside the App:loadPlugins() method (as you can see below) but without success too.

            void App::loadPlugins(const QStringList pluginsList)
            {
                foreach(QString file, pluginsList) {
            
                    QPluginLoader loader(file);
            
                    // Error checking:
                    if (!loader.load()) {
                        sendErrorMsg(tr("%1: ").arg(loader.errorString()));
                        continue;
                    }
            
                    // Get and display the plugin file name:
                    const QStringList pathSplited = loader.fileName().split("/");
                    const QString fileName = pathSplited.last();
                    sendStatusMsg(tr("Loading plugin: %1").arg(fileName));
            
                    // Cast plugin interface:
                    Plugin_API* plugin = qobject_cast<Plugin_API*>(loader.instance());
            
                    // Error chekcing: nullptr
                    if (!plugin) {
                        sendErrorMsg(tr("Wrong Plugin API! Could not cast: %1").arg(loader.fileName()));
                        continue;
                    }
            
                    // ===== CONNECT ALL SIGNALS /  SLOTS ===== //
                    bool conn1 = connect(plugin, &Plugin_API::sendMsg, this, &App::receivedMsg);
                    bool conn2 = connect(plugin, &Plugin_API::savePluginSettings, this, &App::receivedPluginSettings);
            
                    bool allConnections = conn1 & conn2;
            
                    if (!allConnections) {
                        sendErrorMsg(tr("Unable to connect: %1").arg(plugin->getName()));
                        continue;
                    }
            
                    pluginInstance = plugin; // TRY TO USE THE POINTER
            
                    // Store the plugin in a map:
                    _pluginsMapMap[plugin->getType()][plugin->getName()] = plugin;
                }
            }
            

            Could you please help me a little bit more?
            How can I fix it?

            jsulmJ Offline
            jsulmJ Offline
            jsulm
            Lifetime Qt Champion
            wrote on last edited by
            #8

            @fem_dev said in connect: External "C" function:

            In my main application project, I opened the main GUI window Widget (called: App.cpp) and tried to add this line below:

            This does not make sense as pluginInstance is declared in the plug-in NOT in the application! You do not need that in main application at all - simply include the header file which contains extern Plugin_API *pluginInstance; - this is what I actually suggested before.
            To make it short:

            • Add extern Plugin_API *pluginInstance; to the header file inside plug-in NOT cpp file
            • Add Plugin_API *pluginInstance = nullptr; to the corresponding cpp file inside plug-in
            • Do NOT add Plugin_API *pluginInstance = nullptr; in main application
            • Read about "extern", for example https://riptutorial.com/cplusplus/example/28730/extern

            But, I'm wondering why you don't simply add pluginInstance as static member to Plugin_API...

            https://forum.qt.io/topic/113070/qt-code-of-conduct

            F 1 Reply Last reply
            3
            • F fem_dev

              @JonB Almost there...

              My shared library (plugin) have a Interface Class called Plugin_API as you can see below:

              class PLUGIN_EXPORT Plugin : public Plugin_API
              {
                  Q_OBJECT
                  Q_PLUGIN_METADATA(IID "com.rotortest.plugin")
                  Q_INTERFACES(Plugin_API)
              ...
              }
              

              So, inside my main application I have the same Plugin_API Interface...not the Plugin class.
              I think that the extern variable declaration must be PluginAPI type in both Qt projects (plugin and main application), right?

              #include <iostream>
              #include "plugin.h"
              #include "dialog.h"
              
              extern Plugin_API *pluginInstance; // Changed from 'Plugin' to 'Plugin_API'
              
              Plugin::Plugin(QObject* parent)
              {
              }
              
              void Plugin::receivedMsg(int msgType, char* msg)
              {
              }
              
              void fortranMsg(int msgType, char* msg)
              {
                  std::cout << msgType << " | " << msg << std::endl;
              
                  if (pluginInstance)
                       pluginInstance->receivedMsg(msgType, msg);
              }
              

              In my main application project, I opened the main GUI window Widget (called: App.cpp) and tried to add this line below:

              #include "app.h"
              #include "ui_app.h"
              
              Plugin_API *pluginInstance = nullptr;
              
              App::App(QWidget *parent)
                  : QMainWindow(parent)
                  , ui(new Ui::App)
              {
                  ui->setupUi(this);
              ...
              }
              

              But I got the same run time error:

              libLobular-Bearing.so: undefined symbol: pluginInstance
              

              I tried to change the pointer value inside the App:loadPlugins() method (as you can see below) but without success too.

              void App::loadPlugins(const QStringList pluginsList)
              {
                  foreach(QString file, pluginsList) {
              
                      QPluginLoader loader(file);
              
                      // Error checking:
                      if (!loader.load()) {
                          sendErrorMsg(tr("%1: ").arg(loader.errorString()));
                          continue;
                      }
              
                      // Get and display the plugin file name:
                      const QStringList pathSplited = loader.fileName().split("/");
                      const QString fileName = pathSplited.last();
                      sendStatusMsg(tr("Loading plugin: %1").arg(fileName));
              
                      // Cast plugin interface:
                      Plugin_API* plugin = qobject_cast<Plugin_API*>(loader.instance());
              
                      // Error chekcing: nullptr
                      if (!plugin) {
                          sendErrorMsg(tr("Wrong Plugin API! Could not cast: %1").arg(loader.fileName()));
                          continue;
                      }
              
                      // ===== CONNECT ALL SIGNALS /  SLOTS ===== //
                      bool conn1 = connect(plugin, &Plugin_API::sendMsg, this, &App::receivedMsg);
                      bool conn2 = connect(plugin, &Plugin_API::savePluginSettings, this, &App::receivedPluginSettings);
              
                      bool allConnections = conn1 & conn2;
              
                      if (!allConnections) {
                          sendErrorMsg(tr("Unable to connect: %1").arg(plugin->getName()));
                          continue;
                      }
              
                      pluginInstance = plugin; // TRY TO USE THE POINTER
              
                      // Store the plugin in a map:
                      _pluginsMapMap[plugin->getType()][plugin->getName()] = plugin;
                  }
              }
              

              Could you please help me a little bit more?
              How can I fix it?

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by
              #9

              @fem_dev
              Briefly, I had slightly misunderstood, and taken your word that pluginInstance was to be defined in your main program. From @jsulm I now understand it is to work the other way round: you will define it in your shared library, and export it (extern) to be accessible from your main. The explanation about extern Plugin_API *pluginInstance declaration can appear many times (e.g. in a .h file) while the Plugin_API *pluginInstance definition must appear just once in a .cpp file remains the same.

              You should follow exactly what @jsulm has instructed. If as he says you do not need to access pluginInstance outside of the shared library at all, you may be able to just define it as static there.

              1 Reply Last reply
              1
              • F fem_dev

                Thank you @JKSH for your quick response...

                @JKSH said in connect: External "C" function:

                There are many ways you could implement the exporting function.

                I think that I need some help to understand in which scope should I write this lines...

                The problem is: Only inside the main application I can write something like this:

                Plugin *pluginInstance = nullptr; // This pointer can be updated when you construct your plugin object
                

                Because each plugin is loaded by the main application using QPluginLoader.
                So, I think that I can't use this line above inside the Plugin class. Am I right?

                Here is my plugin.h header file:

                #include "dialog.h"
                #include "plugin_global.h"
                #include "plugin_qt_api.h"
                
                // Fortran subroutines
                extern "C" {
                    void callFortran(...input arguments ....);
                    void fortranMsg(int msgType, char* msg);
                }
                
                class PLUGIN_EXPORT Plugin : public Plugin_API
                {
                    Q_OBJECT
                    Q_PLUGIN_METADATA(IID "com.rotortest.plugin")
                    Q_INTERFACES(Plugin_API)
                
                private:
                    Dialog _ui;
                
                public:
                
                    explicit Plugin(QObject* parent = nullptr);
                    ~Plugin();
                
                    //... All Methods override
                
                    void receiveMsg(int msgType, char* msg);
                };
                

                Here is my plugin.cpp implementation:

                #include <iostream>
                #include "plugin.h"
                #include "dialog.h"
                
                Plugin::Plugin(QObject* parent)
                {
                }
                
                Plugin::~Plugin()
                {
                }
                
                void Plugin::receivedMsg(int msgType, char* msg)
                {
                
                }
                
                void fortranMsg(int msgType, char* msg)
                {
                    std::cout << msgType << " | " << msg << std::endl;
                
                    // SEND DATA TO A PLUGIN METHOD
                    // HOW?
                }
                

                Could you help me pass this data from the fortranMsg () function to the Plugin :: receivedMsg () method?

                A first thought that comes to mind is that I should try to make this connection entirely within the shared library (plugin) project, without resorting to the main application project.
                Or is there a better way to "connect" via the main application?

                JKSHJ Offline
                JKSHJ Offline
                JKSH
                Moderators
                wrote on last edited by
                #10

                @fem_dev said in connect: External "C" function:

                Because each plugin is loaded by the main application using QPluginLoader.
                So, I think that I can't use this line above inside the Plugin class. Am I right?

                You are right, the example code that I wrote must be placed in your main application, not your plugin.

                Note: That example expects a single plugin instance. If you want to load multiple plugins at the same time, then you'll need a vector of pointers, not just a single pointer.

                A first thought that comes to mind is that I should try to make this connection entirely within the shared library (plugin) project, without resorting to the main application project.

                I don't think that's a good design. A plugin should not be aware of the main application, so a plugin shouldn't be expected to know that fortranMsg() exists.

                The main application should load the plugin and make all necessary "connections" to the plugin.

                Or is there a better way to "connect" via the main application?

                Let's step back a bit. Ignore the Fortran code for now.

                How do you currently pass any data from your main application into your plugin objects?

                Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                1 Reply Last reply
                3
                • jsulmJ jsulm

                  @fem_dev said in connect: External "C" function:

                  In my main application project, I opened the main GUI window Widget (called: App.cpp) and tried to add this line below:

                  This does not make sense as pluginInstance is declared in the plug-in NOT in the application! You do not need that in main application at all - simply include the header file which contains extern Plugin_API *pluginInstance; - this is what I actually suggested before.
                  To make it short:

                  • Add extern Plugin_API *pluginInstance; to the header file inside plug-in NOT cpp file
                  • Add Plugin_API *pluginInstance = nullptr; to the corresponding cpp file inside plug-in
                  • Do NOT add Plugin_API *pluginInstance = nullptr; in main application
                  • Read about "extern", for example https://riptutorial.com/cplusplus/example/28730/extern

                  But, I'm wondering why you don't simply add pluginInstance as static member to Plugin_API...

                  F Offline
                  F Offline
                  fem_dev
                  wrote on last edited by fem_dev
                  #11

                  @jsulm thank you...I'm almost there...
                  Here are my modifications:

                  Here is my plugin.h header file:

                  #include "dialog.h"
                  #include "plugin_global.h"
                  #include "plugin_qt_api.h"
                  
                  extern Plugin_API *pluginInstance; // FIRST MODIFICATION
                  
                  // Fortran interface
                  extern "C" {
                      void fortranMsg(int msgType, char* msg);
                  }
                  
                  class PLUGIN_EXPORT Plugin : public Plugin_API
                  {
                      Q_OBJECT
                      Q_PLUGIN_METADATA(IID "com.rotortest.plugin")
                      Q_INTERFACES(Plugin_API)
                  
                  private:
                      Dialog _ui;
                  
                  public:
                  
                      explicit Plugin(QObject* parent = nullptr);
                      ~Plugin();
                  
                      ...
                  }
                  

                  Here is my plugin.cpp implementation file:

                  #include "plugin.h"
                  #include <iostream>
                  
                  #include "dialog.h"
                  
                  Plugin_API* pluginInstance = nullptr; // SECOND MODIFICATION
                  
                  Plugin::Plugin(QObject* parent)
                  {
                      Q_UNUSED(parent)
                  }
                  
                  // Other Plugin method implementations...
                  

                  And inside the plugin.cpp I have:

                  void fortranMsg(int msgType, char* msg)
                  {
                      std::cout << msgType << " | " << msg << std::endl; // PRINT THE MSG IN THE Qt CONSOLE OK
                  
                      if (pluginInstance) {
                          pluginInstance->sendStatusMsg(QString(msg));
                      } else {
                          std::cout << "pluginInstance is NULL" << std::endl; // ALWAYS NULLPTR
                      }
                  }
                  

                  I do NOT declared `pluginInstance` in my `main application` // LAST MODIFICATION
                  

                  I got a clean build. No errors, no warnings! All good!
                  And I don't got any run-time erros, BUT I got always the same console message:

                  pluginInstance is NULL
                  

                  After that, I tried too:

                  Plugin_API* pluginInstance = nullptr; // SECOND MODIFICATION
                  
                  Plugin::Plugin(QObject* parent)
                  {
                      Q_UNUSED(parent)
                      
                      pluginInstance = new Plugin; // CREATE A VALID INSTANCE
                  }
                  

                  In this case, the pluginInstance is NULL console message disapears (the pointer is valid), BUT it is not calling correctly the Plugin::sendStatusMsg() method as I want.
                  So, I don't know why, I don't get the sent plugin message in my main application.

                  @JKSH here is how I communicate my own Plugin with my main application:
                  First, the plugin_qt_api.h:

                  #ifndef PLUGIN_QT_API_H
                  #define PLUGIN_QT_API_H
                  
                  #include <QtPlugin>
                  #include <QString>
                  
                  #include "message_types.h"
                  
                  class Plugin_API : public QObject
                  {
                      Q_OBJECT
                  
                  public:
                       Plugin_API()  {}
                  
                      virtual ~Plugin_API() = default;
                  
                      ...
                      
                      virtual void sendStatusMsg(const QString& msg) = 0;
                  
                  signals:
                      void sendMsg(QString source, MSG_TYPE msgType, QString msg);
                  };
                  
                  Q_DECLARE_INTERFACE(Plugin_API, "com.rotortest.plugin")
                  
                  #endif // PLUGIN_QT_API_H
                  

                  Second, the plugin.h:

                  #include "plugin_global.h"
                  #include "plugin_qt_api.h"
                  
                  extern Plugin_API *pluginInstance;
                  
                  // Fortran subroutines
                  extern "C" {
                      void fortranMsg(int msgType, char* msg);
                  }
                  
                  class PLUGIN_EXPORT Plugin : public Plugin_API
                  {
                      Q_OBJECT
                      Q_PLUGIN_METADATA(IID "com.rotortest.plugin")
                      Q_INTERFACES(Plugin_API)
                  
                  public:
                  
                      explicit Plugin(QObject* parent = nullptr);
                  
                      ~Plugin();
                  
                      ...
                      void sendStatusMsg(const QString &msg) override;
                  };
                  

                  Finally, the Plugin::sendStatusMsg() method implementation inside the plugin.cpp file:

                  void Plugin::sendStatusMsg(const QString& msg) {
                      emit sendMsg("My Plugin", MSG_TYPE::STATUS_MSG, msg);
                  }
                  

                  This plugin method works good if I call it from a method inside the Plugin class. No problems here!
                  My problem is ONLY when I have to call this method from the fortranMsg() function. Because it is a function and NOT a Plugin method.

                  So, when my Fortran send a message to the C++ side, I got the message correctly in the fortranMsg() function (I can see it on Qt console), but I don't know how to pass this received message to the Plugin::sendStatusMsg() method.

                  I want to do that to enable my plugins always use the same plugin method to send messages from the plugin side to my main application.

                  As you can see above, inside my main application, I have a method called App::loadPlugin().
                  Inside of it, I have:

                  @fem_dev said in connect: External "C" function:

                  bool conn1 = connect(plugin, &Plugin_API::sendMsg, this, &App::receivedMsg);

                  Could you help me?

                  F 1 Reply Last reply
                  0
                  • F fem_dev

                    @jsulm thank you...I'm almost there...
                    Here are my modifications:

                    Here is my plugin.h header file:

                    #include "dialog.h"
                    #include "plugin_global.h"
                    #include "plugin_qt_api.h"
                    
                    extern Plugin_API *pluginInstance; // FIRST MODIFICATION
                    
                    // Fortran interface
                    extern "C" {
                        void fortranMsg(int msgType, char* msg);
                    }
                    
                    class PLUGIN_EXPORT Plugin : public Plugin_API
                    {
                        Q_OBJECT
                        Q_PLUGIN_METADATA(IID "com.rotortest.plugin")
                        Q_INTERFACES(Plugin_API)
                    
                    private:
                        Dialog _ui;
                    
                    public:
                    
                        explicit Plugin(QObject* parent = nullptr);
                        ~Plugin();
                    
                        ...
                    }
                    

                    Here is my plugin.cpp implementation file:

                    #include "plugin.h"
                    #include <iostream>
                    
                    #include "dialog.h"
                    
                    Plugin_API* pluginInstance = nullptr; // SECOND MODIFICATION
                    
                    Plugin::Plugin(QObject* parent)
                    {
                        Q_UNUSED(parent)
                    }
                    
                    // Other Plugin method implementations...
                    

                    And inside the plugin.cpp I have:

                    void fortranMsg(int msgType, char* msg)
                    {
                        std::cout << msgType << " | " << msg << std::endl; // PRINT THE MSG IN THE Qt CONSOLE OK
                    
                        if (pluginInstance) {
                            pluginInstance->sendStatusMsg(QString(msg));
                        } else {
                            std::cout << "pluginInstance is NULL" << std::endl; // ALWAYS NULLPTR
                        }
                    }
                    

                    I do NOT declared `pluginInstance` in my `main application` // LAST MODIFICATION
                    

                    I got a clean build. No errors, no warnings! All good!
                    And I don't got any run-time erros, BUT I got always the same console message:

                    pluginInstance is NULL
                    

                    After that, I tried too:

                    Plugin_API* pluginInstance = nullptr; // SECOND MODIFICATION
                    
                    Plugin::Plugin(QObject* parent)
                    {
                        Q_UNUSED(parent)
                        
                        pluginInstance = new Plugin; // CREATE A VALID INSTANCE
                    }
                    

                    In this case, the pluginInstance is NULL console message disapears (the pointer is valid), BUT it is not calling correctly the Plugin::sendStatusMsg() method as I want.
                    So, I don't know why, I don't get the sent plugin message in my main application.

                    @JKSH here is how I communicate my own Plugin with my main application:
                    First, the plugin_qt_api.h:

                    #ifndef PLUGIN_QT_API_H
                    #define PLUGIN_QT_API_H
                    
                    #include <QtPlugin>
                    #include <QString>
                    
                    #include "message_types.h"
                    
                    class Plugin_API : public QObject
                    {
                        Q_OBJECT
                    
                    public:
                         Plugin_API()  {}
                    
                        virtual ~Plugin_API() = default;
                    
                        ...
                        
                        virtual void sendStatusMsg(const QString& msg) = 0;
                    
                    signals:
                        void sendMsg(QString source, MSG_TYPE msgType, QString msg);
                    };
                    
                    Q_DECLARE_INTERFACE(Plugin_API, "com.rotortest.plugin")
                    
                    #endif // PLUGIN_QT_API_H
                    

                    Second, the plugin.h:

                    #include "plugin_global.h"
                    #include "plugin_qt_api.h"
                    
                    extern Plugin_API *pluginInstance;
                    
                    // Fortran subroutines
                    extern "C" {
                        void fortranMsg(int msgType, char* msg);
                    }
                    
                    class PLUGIN_EXPORT Plugin : public Plugin_API
                    {
                        Q_OBJECT
                        Q_PLUGIN_METADATA(IID "com.rotortest.plugin")
                        Q_INTERFACES(Plugin_API)
                    
                    public:
                    
                        explicit Plugin(QObject* parent = nullptr);
                    
                        ~Plugin();
                    
                        ...
                        void sendStatusMsg(const QString &msg) override;
                    };
                    

                    Finally, the Plugin::sendStatusMsg() method implementation inside the plugin.cpp file:

                    void Plugin::sendStatusMsg(const QString& msg) {
                        emit sendMsg("My Plugin", MSG_TYPE::STATUS_MSG, msg);
                    }
                    

                    This plugin method works good if I call it from a method inside the Plugin class. No problems here!
                    My problem is ONLY when I have to call this method from the fortranMsg() function. Because it is a function and NOT a Plugin method.

                    So, when my Fortran send a message to the C++ side, I got the message correctly in the fortranMsg() function (I can see it on Qt console), but I don't know how to pass this received message to the Plugin::sendStatusMsg() method.

                    I want to do that to enable my plugins always use the same plugin method to send messages from the plugin side to my main application.

                    As you can see above, inside my main application, I have a method called App::loadPlugin().
                    Inside of it, I have:

                    @fem_dev said in connect: External "C" function:

                    bool conn1 = connect(plugin, &Plugin_API::sendMsg, this, &App::receivedMsg);

                    Could you help me?

                    F Offline
                    F Offline
                    fem_dev
                    wrote on last edited by fem_dev
                    #12

                    @fem_dev Thank you @JKSH @jsulm and @JonB for all help in this topic! I really need to say "thank you"! You all are great!

                    With your help I finally solve this problem.

                    Here is my plugin.h header file:

                    extern Plugin_API *pluginInstance; // <-- 1. CREATE A GLOBAL INTERFACE CLASS POINTER
                    
                    extern "C" {
                        void fortranMsg(int msgType, char* msg);
                    }
                    
                    class PLUGIN_EXPORT Plugin : public Plugin_API
                    {
                        Q_OBJECT
                        Q_PLUGIN_METADATA(IID "com.rotortest.plugin")
                        Q_INTERFACES(Plugin_API)
                    
                    public: 
                        ...
                        void sendStatusMsg(const QString &msg) override;
                    }
                    

                    Here is my plugin.cpp implementation file:

                    Plugin_API* pluginInstance = nullptr; // <-- 2. Init the global pointer to nullptr
                    
                    Plugin::Plugin(QObject* parent)
                    {
                        pluginInstance = this; // <-- 3. Point to the current object
                    }
                    

                    Now, I can use the global variable pluginInstance inside a pure function too.
                    With this pointer, I can call any Plugin method from any pure function. Like:

                    void fortranMsg(int msgType, char* msg)
                    {
                        pluginInstance->sendStatusMsg(QString(msg));    
                    }
                    

                    That's it!

                    Thank you all again!

                    1 Reply Last reply
                    1
                    • JKSHJ Offline
                      JKSHJ Offline
                      JKSH
                      Moderators
                      wrote on last edited by
                      #13

                      @fem_dev, you're welcome. Happy coding! :)

                      I'm curious though: It looks like your app only loads 1 instance of the plugin, is that right? If that's the case, what is the purpose of having a Plugin API?

                      Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                      F 1 Reply Last reply
                      0
                      • JKSHJ JKSH

                        @fem_dev, you're welcome. Happy coding! :)

                        I'm curious though: It looks like your app only loads 1 instance of the plugin, is that right? If that's the case, what is the purpose of having a Plugin API?

                        F Offline
                        F Offline
                        fem_dev
                        wrote on last edited by
                        #14

                        @JKSH said in connect: External "C" function:

                        only loads 1 instance of the plugin

                        No @JKSH ...my main application should load many plugins...

                        What part of my code above made you think that my main application only loads a single plugin?

                        Did I write something wrong?

                        JKSHJ 1 Reply Last reply
                        0
                        • F fem_dev

                          @JKSH said in connect: External "C" function:

                          only loads 1 instance of the plugin

                          No @JKSH ...my main application should load many plugins...

                          What part of my code above made you think that my main application only loads a single plugin?

                          Did I write something wrong?

                          JKSHJ Offline
                          JKSHJ Offline
                          JKSH
                          Moderators
                          wrote on last edited by JKSH
                          #15

                          @fem_dev said in connect: External "C" function:

                          No @JKSH ...my main application should load many plugins...

                          What part of my code above made you think that my main application only loads a single plugin?

                          You only have 1 pluginInstance pointer. That means fortranMsg() can only send the message to 1 plugin.

                          Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                          F 1 Reply Last reply
                          0
                          • JKSHJ JKSH

                            @fem_dev said in connect: External "C" function:

                            No @JKSH ...my main application should load many plugins...

                            What part of my code above made you think that my main application only loads a single plugin?

                            You only have 1 pluginInstance pointer. That means fortranMsg() can only send the message to 1 plugin.

                            F Offline
                            F Offline
                            fem_dev
                            wrote on last edited by
                            #16

                            @JKSH said in connect: External "C" function:

                            You only have 1 pluginInstance pointer.

                            Yes! That's right!

                            Inside my plugin, I have only one pluginInstance pointer.

                            Each plugin is a isolated Qt shared library project. So inside of each plugin I must have only your own pluginInstance pointer.

                            My main application will load all compiled plugins after that.

                            1 Reply Last reply
                            0

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved