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. QApplication in a std::thread that lives in a DLL
QtWS25 Last Chance

QApplication in a std::thread that lives in a DLL

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 3 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.
  • E Offline
    E Offline
    elinmerl
    wrote on last edited by
    #1

    Hello everybody,
    I'm still pretty much at the beginning with QT. But before I can get into it, I have to know if what I have in mind will work.
    We have an application which based on a very old compiler and framwork. The idea is port step by step the GUI and the logic to QT
    by using a mordern compiler.
    For this I made DLL and start QApplication in a std::thread. This looks like this:

    static std::thread * g_qAppThread = nullptr;
    static QApplication *g_qApp = nullptr;
    static GuiLauncher * g_guiLauncher = nullptr;
    
    void threadFunc()
    {
        static int argc = 1;
        const static char *argv[] = { "thread", nullptr };
        g_qApp = new QApplication( argc, const_cast<char**>(argv));
        g_qApp->exec();
        delete g_qApp;
        g_qApp = nullptr;
        std::cout << "threadFunc() end" << std::endl;
    }
    
    
    QT_IN_DLLSHARED_EXPORT int startQtApplication()
    {
        if( g_qAppThread != nullptr )
        {
            std::cout << "startApplication(): thread already running" << std::endl;
            return -1;
        }
    
        g_qAppThread = new std::thread( &threadFunc );
    
        // Now wait until the EventDispatcher of QApplication is running.
        using namespace std::chrono_literals;
        while( g_qApp == nullptr || ! g_qApp->eventDispatcher() )
            std::this_thread::sleep_for( 10ms );
        g_qAppThread->detach();
    
        g_qApp->setQuitOnLastWindowClosed( false );
        g_guiLauncher = new GuiLauncher;
        g_guiLauncher->moveToThread( QApplication::instance()->thread() );
    
        return 1;
    }
    
    QT_IN_DLLSHARED_EXPORT void showTestDialog( const char * name, const char * vorname )
    {
        if( g_qApp == nullptr )
            startQtApplication();
    
    	g_qApp->postEvent( g_guiLauncher, new TestDialogEvent( name, vorname, EventWrapper::instance().getEventType( Functions::TEST_DIALOG ) ) );
    }
    

    My Test is to open a QMessageBox from a DLL function call (see above showMessageBox()).
    In the internet I found several postings with the same problem. But most answers did not work. The only way I get it to work
    is to use QApplication::postEvent().

    For that implement the class GuiLauncher.

    class GuiLauncher : public QObject
    {
        Q_OBJECT
    
    public:
        GuiLauncher(){};
    
        ~GuiLauncher() override {};
    
        bool event( QEvent * ev ) override
    	{
    		if( ev->type() == EventWrapper::instance().getEventType( Functions::TEST_DIALOG ) )
    		{
    			TestDialogEvent * testDialogEvent = dynamic_cast< TestDialogEvent *>( ev );
    			showTestDialog( testDialogEvent->getName(), testDialogEvent->getVorname() );
    		}
    		return false;
    	}
    
    private:
        void showTestDialog( const QString & name, const QString & vorname );
    	{
    		TestDialog * dlg = new TestDialog( nullptr, name, vorname );
    		dlg->setModal( true );
    	    dlg->setAttribute( Qt::WA_DeleteOnClose, true );
    		dlg->show();
    	}
    
    };
    

    The class TestDialog inherit from QDialog and has two LineEdit controls.

    This all works. But I find it very cumbersome to let everything run through events.
    Is there another way? On the Internet I have found solutions using QMetaObject::invokeMethod().
    But that didn't work for me. The method was not called. I also found solutions using
    signal/slot. But even that didn't work for me.

    The next problem is that the DLL function showTestDialog() should wait for the dialog to close.
    I don't have a solution yet.

    Anybody got an idea?

    aha_1980A JKSHJ 2 Replies Last reply
    0
    • E elinmerl

      Hello everybody,
      I'm still pretty much at the beginning with QT. But before I can get into it, I have to know if what I have in mind will work.
      We have an application which based on a very old compiler and framwork. The idea is port step by step the GUI and the logic to QT
      by using a mordern compiler.
      For this I made DLL and start QApplication in a std::thread. This looks like this:

      static std::thread * g_qAppThread = nullptr;
      static QApplication *g_qApp = nullptr;
      static GuiLauncher * g_guiLauncher = nullptr;
      
      void threadFunc()
      {
          static int argc = 1;
          const static char *argv[] = { "thread", nullptr };
          g_qApp = new QApplication( argc, const_cast<char**>(argv));
          g_qApp->exec();
          delete g_qApp;
          g_qApp = nullptr;
          std::cout << "threadFunc() end" << std::endl;
      }
      
      
      QT_IN_DLLSHARED_EXPORT int startQtApplication()
      {
          if( g_qAppThread != nullptr )
          {
              std::cout << "startApplication(): thread already running" << std::endl;
              return -1;
          }
      
          g_qAppThread = new std::thread( &threadFunc );
      
          // Now wait until the EventDispatcher of QApplication is running.
          using namespace std::chrono_literals;
          while( g_qApp == nullptr || ! g_qApp->eventDispatcher() )
              std::this_thread::sleep_for( 10ms );
          g_qAppThread->detach();
      
          g_qApp->setQuitOnLastWindowClosed( false );
          g_guiLauncher = new GuiLauncher;
          g_guiLauncher->moveToThread( QApplication::instance()->thread() );
      
          return 1;
      }
      
      QT_IN_DLLSHARED_EXPORT void showTestDialog( const char * name, const char * vorname )
      {
          if( g_qApp == nullptr )
              startQtApplication();
      
      	g_qApp->postEvent( g_guiLauncher, new TestDialogEvent( name, vorname, EventWrapper::instance().getEventType( Functions::TEST_DIALOG ) ) );
      }
      

      My Test is to open a QMessageBox from a DLL function call (see above showMessageBox()).
      In the internet I found several postings with the same problem. But most answers did not work. The only way I get it to work
      is to use QApplication::postEvent().

      For that implement the class GuiLauncher.

      class GuiLauncher : public QObject
      {
          Q_OBJECT
      
      public:
          GuiLauncher(){};
      
          ~GuiLauncher() override {};
      
          bool event( QEvent * ev ) override
      	{
      		if( ev->type() == EventWrapper::instance().getEventType( Functions::TEST_DIALOG ) )
      		{
      			TestDialogEvent * testDialogEvent = dynamic_cast< TestDialogEvent *>( ev );
      			showTestDialog( testDialogEvent->getName(), testDialogEvent->getVorname() );
      		}
      		return false;
      	}
      
      private:
          void showTestDialog( const QString & name, const QString & vorname );
      	{
      		TestDialog * dlg = new TestDialog( nullptr, name, vorname );
      		dlg->setModal( true );
      	    dlg->setAttribute( Qt::WA_DeleteOnClose, true );
      		dlg->show();
      	}
      
      };
      

      The class TestDialog inherit from QDialog and has two LineEdit controls.

      This all works. But I find it very cumbersome to let everything run through events.
      Is there another way? On the Internet I have found solutions using QMetaObject::invokeMethod().
      But that didn't work for me. The method was not called. I also found solutions using
      signal/slot. But even that didn't work for me.

      The next problem is that the DLL function showTestDialog() should wait for the dialog to close.
      I don't have a solution yet.

      Anybody got an idea?

      aha_1980A Offline
      aha_1980A Offline
      aha_1980
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @elinmerl said in QApplication in a std::thread that lives in a DLL:

      We have an application which based on a very old compiler and framwork.

      Which one? If it is Visual studio with MFC, there is a possibility for the migration: https://docs.huihoo.com/qt/solutions/4/qtwinmigrate/winmigrate-walkthrough.html

      Otherwise you should give some more information about the old app.

      Is logic and GUI already separated? That would make things easier...

      Qt has to stay free or it will die.

      E 1 Reply Last reply
      1
      • E elinmerl

        Hello everybody,
        I'm still pretty much at the beginning with QT. But before I can get into it, I have to know if what I have in mind will work.
        We have an application which based on a very old compiler and framwork. The idea is port step by step the GUI and the logic to QT
        by using a mordern compiler.
        For this I made DLL and start QApplication in a std::thread. This looks like this:

        static std::thread * g_qAppThread = nullptr;
        static QApplication *g_qApp = nullptr;
        static GuiLauncher * g_guiLauncher = nullptr;
        
        void threadFunc()
        {
            static int argc = 1;
            const static char *argv[] = { "thread", nullptr };
            g_qApp = new QApplication( argc, const_cast<char**>(argv));
            g_qApp->exec();
            delete g_qApp;
            g_qApp = nullptr;
            std::cout << "threadFunc() end" << std::endl;
        }
        
        
        QT_IN_DLLSHARED_EXPORT int startQtApplication()
        {
            if( g_qAppThread != nullptr )
            {
                std::cout << "startApplication(): thread already running" << std::endl;
                return -1;
            }
        
            g_qAppThread = new std::thread( &threadFunc );
        
            // Now wait until the EventDispatcher of QApplication is running.
            using namespace std::chrono_literals;
            while( g_qApp == nullptr || ! g_qApp->eventDispatcher() )
                std::this_thread::sleep_for( 10ms );
            g_qAppThread->detach();
        
            g_qApp->setQuitOnLastWindowClosed( false );
            g_guiLauncher = new GuiLauncher;
            g_guiLauncher->moveToThread( QApplication::instance()->thread() );
        
            return 1;
        }
        
        QT_IN_DLLSHARED_EXPORT void showTestDialog( const char * name, const char * vorname )
        {
            if( g_qApp == nullptr )
                startQtApplication();
        
        	g_qApp->postEvent( g_guiLauncher, new TestDialogEvent( name, vorname, EventWrapper::instance().getEventType( Functions::TEST_DIALOG ) ) );
        }
        

        My Test is to open a QMessageBox from a DLL function call (see above showMessageBox()).
        In the internet I found several postings with the same problem. But most answers did not work. The only way I get it to work
        is to use QApplication::postEvent().

        For that implement the class GuiLauncher.

        class GuiLauncher : public QObject
        {
            Q_OBJECT
        
        public:
            GuiLauncher(){};
        
            ~GuiLauncher() override {};
        
            bool event( QEvent * ev ) override
        	{
        		if( ev->type() == EventWrapper::instance().getEventType( Functions::TEST_DIALOG ) )
        		{
        			TestDialogEvent * testDialogEvent = dynamic_cast< TestDialogEvent *>( ev );
        			showTestDialog( testDialogEvent->getName(), testDialogEvent->getVorname() );
        		}
        		return false;
        	}
        
        private:
            void showTestDialog( const QString & name, const QString & vorname );
        	{
        		TestDialog * dlg = new TestDialog( nullptr, name, vorname );
        		dlg->setModal( true );
        	    dlg->setAttribute( Qt::WA_DeleteOnClose, true );
        		dlg->show();
        	}
        
        };
        

        The class TestDialog inherit from QDialog and has two LineEdit controls.

        This all works. But I find it very cumbersome to let everything run through events.
        Is there another way? On the Internet I have found solutions using QMetaObject::invokeMethod().
        But that didn't work for me. The method was not called. I also found solutions using
        signal/slot. But even that didn't work for me.

        The next problem is that the DLL function showTestDialog() should wait for the dialog to close.
        I don't have a solution yet.

        Anybody got an idea?

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

        @elinmerl said in QApplication in a std::thread that lives in a DLL:

        On the Internet I have found solutions using QMetaObject::invokeMethod().
        But that didn't work for me. The method was not called. I also found solutions using
        signal/slot. But even that didn't work for me.

        These can definitely be made to work. Post your code and we'll have a look.

        The next problem is that the DLL function showTestDialog() should wait for the dialog to close.
        I don't have a solution yet.

        Once you get QMetaObject::invokeMethod() working, you can use a Qt::BlockingQueuedConnection to block the caller until the invoked function returns.

        Some other improvements:

        g_qApp = new QApplication( argc, const_cast<char**>(argv));

        No need to use new, just create QApplication on the stack.

        g_qApp->setQuitOnLastWindowClosed( false );

        You're calling this from a different thread to the one that QApplication lives in. That's not supported; instead, call this in startQtApplication()

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

        E 1 Reply Last reply
        6
        • aha_1980A aha_1980

          @elinmerl said in QApplication in a std::thread that lives in a DLL:

          We have an application which based on a very old compiler and framwork.

          Which one? If it is Visual studio with MFC, there is a possibility for the migration: https://docs.huihoo.com/qt/solutions/4/qtwinmigrate/winmigrate-walkthrough.html

          Otherwise you should give some more information about the old app.

          Is logic and GUI already separated? That would make things easier...

          E Offline
          E Offline
          elinmerl
          wrote on last edited by
          #4

          @aha_1980 said in QApplication in a std::thread that lives in a DLL:

          @elinmerl said in QApplication in a std::thread that lives in a DLL:

          We have an application which based on a very old compiler and framwork.

          Which one? If it is Visual studio with MFC, there is a possibility for the migration: https://docs.huihoo.com/qt/solutions/4/qtwinmigrate/winmigrate-walkthrough.html

          Otherwise you should give some more information about the old app.

          The app is build with Borland C++ 5.02 Compiler. And the GUI is built with Borland-OWL.

          Is logic and GUI already separated? That would make things easier...

          The GUI is not separated from the logic. That's why we want to move everything step by step into DLLs and replace the GUI with QT at the same time.

          1 Reply Last reply
          0
          • JKSHJ JKSH

            @elinmerl said in QApplication in a std::thread that lives in a DLL:

            On the Internet I have found solutions using QMetaObject::invokeMethod().
            But that didn't work for me. The method was not called. I also found solutions using
            signal/slot. But even that didn't work for me.

            These can definitely be made to work. Post your code and we'll have a look.

            The next problem is that the DLL function showTestDialog() should wait for the dialog to close.
            I don't have a solution yet.

            Once you get QMetaObject::invokeMethod() working, you can use a Qt::BlockingQueuedConnection to block the caller until the invoked function returns.

            Some other improvements:

            g_qApp = new QApplication( argc, const_cast<char**>(argv));

            No need to use new, just create QApplication on the stack.

            g_qApp->setQuitOnLastWindowClosed( false );

            You're calling this from a different thread to the one that QApplication lives in. That's not supported; instead, call this in startQtApplication()

            E Offline
            E Offline
            elinmerl
            wrote on last edited by
            #5

            @JKSH said in QApplication in a std::thread that lives in a DLL:

            @elinmerl said in QApplication in a std::thread that lives in a DLL:

            On the Internet I have found solutions using QMetaObject::invokeMethod().
            But that didn't work for me. The method was not called. I also found solutions using
            signal/slot. But even that didn't work for me.

            These can definitely be made to work. Post your code and we'll have a look.

            The next problem is that the DLL function showTestDialog() should wait for the dialog to close.
            I don't have a solution yet.

            Once you get QMetaObject::invokeMethod() working, you can use a Qt::BlockingQueuedConnection to block the caller until the invoked function returns.

            Today I found a solution that works with QMetaObject::invokeMethod(). But it's also expensive. So my new showTestDialog() function looks like that:

            QT_IN_DLLSHARED_EXPORT void showTestDialog( HWND parent, const char * name, const char * vorname )
            {
                if( g_qApp == nullptr )
                    startQtApplication();
                QThread thread;
                QEventLoop loop;
                QObject context;
                context.moveToThread( &thread );
                QObject::connect( &thread, &QThread::started, &context, [&]() {
                    std::cout << "QThread started" << std::endl;
                    bool ret = QMetaObject::invokeMethod( g_guiLauncher, "showTestDialog", Qt::BlockingQueuedConnection, Q_ARG( HWND, parent), Q_ARG( QString, name), Q_ARG( QString, vorname ) );
                    std::cout << "showTestDialog(): invokeMethod returned (" << ret << ")" << std::endl;
                    loop.quit();
                });
                thread.start();
                loop.exec();
                thread.quit();
                thread.wait();
            
                std::cout << "showTestDialog(): after postEvent()" << std::endl;
            }
            

            Some other improvements:

            g_qApp = new QApplication( argc, const_cast<char**>(argv));

            No need to use new, just create QApplication on the stack.

            I use it to check if there is a QApp running ist I call a DLL function.

            JKSHJ 1 Reply Last reply
            0
            • E elinmerl

              @JKSH said in QApplication in a std::thread that lives in a DLL:

              @elinmerl said in QApplication in a std::thread that lives in a DLL:

              On the Internet I have found solutions using QMetaObject::invokeMethod().
              But that didn't work for me. The method was not called. I also found solutions using
              signal/slot. But even that didn't work for me.

              These can definitely be made to work. Post your code and we'll have a look.

              The next problem is that the DLL function showTestDialog() should wait for the dialog to close.
              I don't have a solution yet.

              Once you get QMetaObject::invokeMethod() working, you can use a Qt::BlockingQueuedConnection to block the caller until the invoked function returns.

              Today I found a solution that works with QMetaObject::invokeMethod(). But it's also expensive. So my new showTestDialog() function looks like that:

              QT_IN_DLLSHARED_EXPORT void showTestDialog( HWND parent, const char * name, const char * vorname )
              {
                  if( g_qApp == nullptr )
                      startQtApplication();
                  QThread thread;
                  QEventLoop loop;
                  QObject context;
                  context.moveToThread( &thread );
                  QObject::connect( &thread, &QThread::started, &context, [&]() {
                      std::cout << "QThread started" << std::endl;
                      bool ret = QMetaObject::invokeMethod( g_guiLauncher, "showTestDialog", Qt::BlockingQueuedConnection, Q_ARG( HWND, parent), Q_ARG( QString, name), Q_ARG( QString, vorname ) );
                      std::cout << "showTestDialog(): invokeMethod returned (" << ret << ")" << std::endl;
                      loop.quit();
                  });
                  thread.start();
                  loop.exec();
                  thread.quit();
                  thread.wait();
              
                  std::cout << "showTestDialog(): after postEvent()" << std::endl;
              }
              

              Some other improvements:

              g_qApp = new QApplication( argc, const_cast<char**>(argv));

              No need to use new, just create QApplication on the stack.

              I use it to check if there is a QApp running ist I call a DLL function.

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

              @elinmerl said in QApplication in a std::thread that lives in a DLL:

              No need to use new, just create QApplication on the stack.

              I use it to check if there is a QApp running ist I call a DLL function.

              You can take a pointer to a stack-allocated object.

              Anyway, Qt already provides a global pointer to your QApplication: qApp or QApplication::instance(). Furthermore, these pointers are set to nullptr before QApplication is constructed and after it's destroyed.

              Note: There's a minor race condition when you check for == nullptr or != nullptr from another thread, but if you're careful it works well.

              Today I found a solution that works with QMetaObject::invokeMethod(). But it's also expensive. So my new showTestDialog() function looks like that:

              Congrats on finding a solution. Let's simplify things further -- You don't need to construct the QThread, QEventLoop, or QObject:

              // Code that runs in the new thread
              static GuiLauncher * g_guiLauncher = nullptr;
              
              static void threadFunc()
              {
                  static int argc = 1;
                  const static char *argv[] = { "thread", nullptr };
                  QApplication app( argc, const_cast<char**>(argv) );
                  app.setQuitOnLastWindowClosed( false ); // You MUST call QApplication methods in the QApplication thread
                 
                  GuiLauncher launcher;
                  g_guiLauncher = &launcher; // You can get a pointer to a stack-allocated object
              
                  app.exec();
                  g_guiLauncher = nullptr;
                  std::cout << "threadFunc() end" << std::endl;
              }
              
              // Code that initializes the new thread
              static int startQtApplication()
              {
                  if (qApp != nullptr)
                  {
                      std::cout << "startApplication(): thread already running" << std::endl;
                      return -1;
                  }
                  std::thread t(&threadFunc); // Again, you don't need `new`
                  t.detach();
              
                  // Now wait until the GuiLauncher has been created
                  // NOTE: `while (qApp->eventDispatcher() == nullptr)` is not enough!
                  //       Because the event dispatcher is created before GuiLauncher.
                  using namespace std::chrono_literals;
                  while (g_guiLauncher == nullptr)
                      std::this_thread::sleep_for( 10ms );
              
                  return 1;
              }
              
              // Code that you call from your main thread
              // NOTE: I've removed the HWND parameter for clarity
              QT_IN_DLLSHARED_EXPORT void showTestDialog( const char * name, const char * vorname )
              {
                  // WARNING: If this function is called 2x rapidly, the following check will give wrong results
                  if (qApp == nullptr)
                      startQtApplication();
              
                  // You can use your GuiLauncher as the Context object
                  bool ret = QMetaObject::invokeMethod(g_guiLauncher, [=]() {
                      // ASSUMPTION: The method is public and its signature is
                      // GuiLauncher::showTestDialog(const QString &name, const QString &vorname)
                      g_guiLauncher->showTestDialog(QString::fromLatin1(name), QString::fromLatin1(vorname));
                  }, Qt::BlockingQueuedConnection);
              
                  std::cout << "showTestDialog(): invokeMethod returned (" << ret << ")" << std::endl;
              }
              

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

              E 1 Reply Last reply
              2
              • JKSHJ JKSH

                @elinmerl said in QApplication in a std::thread that lives in a DLL:

                No need to use new, just create QApplication on the stack.

                I use it to check if there is a QApp running ist I call a DLL function.

                You can take a pointer to a stack-allocated object.

                Anyway, Qt already provides a global pointer to your QApplication: qApp or QApplication::instance(). Furthermore, these pointers are set to nullptr before QApplication is constructed and after it's destroyed.

                Note: There's a minor race condition when you check for == nullptr or != nullptr from another thread, but if you're careful it works well.

                Today I found a solution that works with QMetaObject::invokeMethod(). But it's also expensive. So my new showTestDialog() function looks like that:

                Congrats on finding a solution. Let's simplify things further -- You don't need to construct the QThread, QEventLoop, or QObject:

                // Code that runs in the new thread
                static GuiLauncher * g_guiLauncher = nullptr;
                
                static void threadFunc()
                {
                    static int argc = 1;
                    const static char *argv[] = { "thread", nullptr };
                    QApplication app( argc, const_cast<char**>(argv) );
                    app.setQuitOnLastWindowClosed( false ); // You MUST call QApplication methods in the QApplication thread
                   
                    GuiLauncher launcher;
                    g_guiLauncher = &launcher; // You can get a pointer to a stack-allocated object
                
                    app.exec();
                    g_guiLauncher = nullptr;
                    std::cout << "threadFunc() end" << std::endl;
                }
                
                // Code that initializes the new thread
                static int startQtApplication()
                {
                    if (qApp != nullptr)
                    {
                        std::cout << "startApplication(): thread already running" << std::endl;
                        return -1;
                    }
                    std::thread t(&threadFunc); // Again, you don't need `new`
                    t.detach();
                
                    // Now wait until the GuiLauncher has been created
                    // NOTE: `while (qApp->eventDispatcher() == nullptr)` is not enough!
                    //       Because the event dispatcher is created before GuiLauncher.
                    using namespace std::chrono_literals;
                    while (g_guiLauncher == nullptr)
                        std::this_thread::sleep_for( 10ms );
                
                    return 1;
                }
                
                // Code that you call from your main thread
                // NOTE: I've removed the HWND parameter for clarity
                QT_IN_DLLSHARED_EXPORT void showTestDialog( const char * name, const char * vorname )
                {
                    // WARNING: If this function is called 2x rapidly, the following check will give wrong results
                    if (qApp == nullptr)
                        startQtApplication();
                
                    // You can use your GuiLauncher as the Context object
                    bool ret = QMetaObject::invokeMethod(g_guiLauncher, [=]() {
                        // ASSUMPTION: The method is public and its signature is
                        // GuiLauncher::showTestDialog(const QString &name, const QString &vorname)
                        g_guiLauncher->showTestDialog(QString::fromLatin1(name), QString::fromLatin1(vorname));
                    }, Qt::BlockingQueuedConnection);
                
                    std::cout << "showTestDialog(): invokeMethod returned (" << ret << ")" << std::endl;
                }
                
                E Offline
                E Offline
                elinmerl
                wrote on last edited by
                #7

                @JKSH Thank you for your simplification! So I can go on and do more tests.

                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