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 Update on Monday, May 27th 2025

connect: External "C" function

Scheduled Pinned Locked Moved Solved General and Desktop
16 Posts 4 Posters 1.8k Views
  • 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

    I developed a Qt GUI C++ shared library (plugin) that contains a Fortran 90 static library inside of it.

    To enable to receive the Fortran data back to C++ side, I created a Fortran/C++ interface and it works great.

    In the C++ side I have:

    external "C" {
        void callFortran(...input arguments ....);
        void fortranMsg(int msgType, char* msg);
    }
    

    So, when Fortran send a message to C++, I already receive that inside of this external C function below:

    void fortranMsg(int msgType, char* msg)
    {
        // Messages from Fortran subroutine to C++ side
        // It is already working!
    }
    

    I would like to connect this fortranMsg() function to a plugin method, like:

    Plugin::Plugin(QObject* parent)
    {
        // WRONG SINTAX: JUST A EXAMPLE
        bool conn = connect(fortranMsg, this, &Plugin::receivedMsg);
    }
    
    Plugin::receivedMsg(int msgType, char* msg)
    {
        // Get that Fortran message inside a plugin method
    }
    

    I don't know if connect is a good way to do that...it is just an example of what I need to do...

    How can I send the data (msgType and msg) from fortranMsg() to a Plugin::receivedMsg()?

    Thank you,

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

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

    How can I send the data (msgType and msg) from fortranMsg() to a Plugin::receivedMsg()?

    Since fortranMsg() is a function that is called by Fortran, you cannot connect it like a signal. Instead, you must add extra code inside fortranMsg():

    void fortranMsg(int msgType, char* msg)
    {
        // Messages from Fortran subroutine to C++ side
        // It is already working!
    
        exportData(msgType, msg); // <-- Add a function call here to pass the data out
    }
    

    There are many ways you could implement the exporting function. For example, you could store a pointer to the plugin object as a global variable and call receivedMsg() directly:

    Plugin *pluginInstance = nullptr; // This pointer can be updated when you construct your plugin object
    
    void fortranMsg(int msgType, char* msg)
    {
        // Messages from Fortran subroutine to C++ side
        // It is already working!
    
        if (pluginInstance)
             pluginInstsance->receivedMsg(msgType, msg);
    }
    

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

    F 1 Reply Last reply
    6
    • JKSHJ JKSH

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

      How can I send the data (msgType and msg) from fortranMsg() to a Plugin::receivedMsg()?

      Since fortranMsg() is a function that is called by Fortran, you cannot connect it like a signal. Instead, you must add extra code inside fortranMsg():

      void fortranMsg(int msgType, char* msg)
      {
          // Messages from Fortran subroutine to C++ side
          // It is already working!
      
          exportData(msgType, msg); // <-- Add a function call here to pass the data out
      }
      

      There are many ways you could implement the exporting function. For example, you could store a pointer to the plugin object as a global variable and call receivedMsg() directly:

      Plugin *pluginInstance = nullptr; // This pointer can be updated when you construct your plugin object
      
      void fortranMsg(int msgType, char* msg)
      {
          // Messages from Fortran subroutine to C++ side
          // It is already working!
      
          if (pluginInstance)
               pluginInstsance->receivedMsg(msgType, msg);
      }
      
      F Offline
      F Offline
      fem_dev
      wrote on last edited by
      #3

      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 JKSHJ 2 Replies Last reply
      0
      • 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