Page 1 of 2 12 LastLast
Results 1 to 20 of 22

Thread: Calling Qt library from non-Qt C++ client

  1. #1
    Join Date
    Jul 2007
    Posts
    121
    Thanks
    38
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Calling Qt library from non-Qt C++ client

    I have a non-Qt client in C++ that I cannot convert to Qt and I also have Qt library that I need to call from this client (all pieces are in Windows). I added couple of exported functions to my library that in turn are calling the global instances of my classes. Everything works fine, I can successfully call them from the straight C++ client. With one caveat - signals seems not to work. My QObject::connect calls all return true, signals are emitted (I can see that in the debugger), but they do not reach the recepient.

    My suspicion is that I am not initializing the global event handling properly.
    I am using QCoreApplication as a global variable and initialize it in the thread. My pseudo code in Qt library looks like this:

    Qt Code:
    1. int _app_i = 1;
    2. char* _app_buf = "";
    3. QCoreApplication _app (_app_i, &_app_buf);
    4. ...
    5. extern "C"
    6. {
    7. bool start() // exported function
    8. {
    9. QThreadPool::globalInstance()->start(new appstarter() ); // see below the implementation of "run"
    10. return true;
    11. }
    12. }
    13.  
    14. void appstarter::run()
    15. {
    16. _app.exec();
    17. int i = 5; // I should not reach this line but I do!. According to docs the exec() call should only return after quit is called.
    18. }
    To copy to clipboard, switch view to plain text mode 

    I know that my library is not unloaded in the C++ client, because I can call other exported functions in any time and they are accessing other global variables, so _app instance exists.


    I will appreciate suggestions/comments to help me solve the problem. As a start - why _app.exec() returns immediately?

    Thanks

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Calling Qt library from non-Qt C++ client

    Why are you using QThreadPool here?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. The following user says thank you to wysota for this useful post:

    QPlace (21st February 2013)

  4. #3
    Join Date
    Jul 2007
    Posts
    121
    Thanks
    38
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Calling Qt library from non-Qt C++ client

    Because ”start” function is an exported one, i.e is called from the client. I expected app.exe() to enter the event loop.

  5. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Calling Qt library from non-Qt C++ client

    It doesn't explain why you use QThreadPool and not QThread. You need to create a QThread instance, create the application instance, move it to the thread, start the thread and call exec from within the thread (e.g. by subclassing and reimplementing run()).
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  6. The following user says thank you to wysota for this useful post:

    QPlace (21st February 2013)

  7. #5
    Join Date
    Jul 2007
    Posts
    121
    Thanks
    38
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Calling Qt library from non-Qt C++ client

    You are correct, it does not explain the choice between QThreadPool and QThread. In my case I don't see any difference between them, since my goal was to start event loop for global QCoreApplication object. Anyway, I changed the code to use QThread and it produced the same result. Interestingly, if I call _app.exec() in start() directly, without the thread usage, it enters the event loop. In case of QThread or QThreadPool usage, it returns immediately.

    Qt Code:
    1. bool start()
    2. {
    3. appstarter* ast = new appstarter();
    4. QThread* wt = new QThread();
    5. QObject::connect(wt, SIGNAL(started()), ast, SLOT(run()));
    6. ast->moveToThread(wt);
    7. wt->start();
    8. // QThreadPool::globalInstance()->start(new appstarter() );
    9. return true;
    10. }
    To copy to clipboard, switch view to plain text mode 

    ... and now I know why. It returns from QCoreApplication::exec() with this:
    if (threadData != QThreadData::current()) {
    qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className());
    return -1;
    }

  8. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Calling Qt library from non-Qt C++ client

    Quote Originally Posted by QPlace View Post
    In my case I don't see any difference between them
    You will if you decide to use anything related to QtConcurrent or QThreadPool on a single core machine inside your Qt code

    Anyway, I changed the code to use QThread and it produced the same result. Interestingly, if I call _app.exec() in start() directly, without the thread usage, it enters the event loop. In case of QThread or QThreadPool usage, it returns immediately.

    Qt Code:
    1. bool start()
    2. {
    3. appstarter* ast = new appstarter();
    4. QThread* wt = new QThread();
    5. QObject::connect(wt, SIGNAL(started()), ast, SLOT(run()));
    6. ast->moveToThread(wt);
    7. wt->start();
    8. // QThreadPool::globalInstance()->start(new appstarter() );
    9. return true;
    10. }
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. class ThreadedApp : public QThread {
    2. public:
    3. ThreadedApp() : QThread() { }
    4. void run() {
    5. char *argv[] = { "myapp" };
    6. QApplication app(1, ; argv);
    7. app.exec(); // or just exec(), try both
    8. }
    9. };
    10. //...
    11. ThreadedApp app;
    12. app.start();
    To copy to clipboard, switch view to plain text mode 

    Edit: remember that all the GUI objects you create need to be pushed to this thread.
    Last edited by wysota; 20th February 2013 at 18:43.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  9. The following user says thank you to wysota for this useful post:

    QPlace (20th February 2013)

  10. #7
    Join Date
    Jul 2007
    Posts
    121
    Thanks
    38
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Calling Qt library from non-Qt C++ client

    No matter what I do I cannot make the signals to fire. QCoreApplication instance is created and event loop enters successfully. I will try to create a test project and post it here shortly.

    Hopefully wysota or someone else can spot a problem.

    Thanks

  11. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Calling Qt library from non-Qt C++ client

    Signals are firing. Slots might not be called because of a missing event loop in the thread that owns receivers of those signals.

    Here is something that works for me. I'm using a C++11 compiler for thread support.

    Qt Code:
    1. #include <QtGui>
    2. #include <thread>
    3.  
    4. void thrmain() {
    5. int argc = 1;
    6. char *argv[] = { "testapp" };
    7. QApplication app(argc, argv);
    8. QPushButton pb("Click");
    9. QObject::connect(&pb, SIGNAL(clicked()), &le, SLOT(clear()));
    10. pb.show();
    11. le.show();
    12. app.exec();
    13. }
    14.  
    15. int main() {
    16. std::thread thr(thrmain);
    17. thr.join();
    18. return 0;
    19. }
    To copy to clipboard, switch view to plain text mode 

    I think the important thing is to not use Qt threads or else Qt will complain about the app being created not in the main thread.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  12. The following user says thank you to wysota for this useful post:

    QPlace (21st February 2013)

  13. #9
    Join Date
    Jul 2007
    Posts
    121
    Thanks
    38
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Calling Qt library from non-Qt C++ client

    You are correct (as usual ). I misspoke, I can see signals being emitted, it is the slots that are not being called. I will check your solution before I continue with test project.

  14. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Calling Qt library from non-Qt C++ client

    One thing that came to my mind... If you wish to use cross-thread signals-slots involving the UI, make sure you explicitly make connections Qt::DirectConnection if the signal is fired by the UI thread and the receiver lives in a thread not controlled by Qt. Otherwise slots will not work properly. Just make sure you do proper synchronization.
    Last edited by wysota; 21st February 2013 at 00:12.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  15. The following user says thank you to wysota for this useful post:

    QPlace (21st February 2013)

  16. #11
    Join Date
    Jul 2007
    Posts
    121
    Thanks
    38
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Calling Qt library from non-Qt C++ client

    I am not using any GUI stuff, so my app is QCoreApplication and not QApplication. Since I moved app.exe under QThread (per your advise) it correctly enters the event loop, so QThread seems not to be the problem. However, I still cannot get my slots being called, regardless of where I instantiate the receiver (in the main thread or in the spawned thread).

    I also tried to use Qt:irectConnection. No luck.

    (In my current version, there are two threads. The child thread is spawned by the main thread where app.exec() is being called. Main thread calls app.exec in it' run method. The child thread instantiate the sender of signals in constructor, it is also the receiver. Child thread connects sender and itself with "connect" and calls "exec()" in its run method.)
    Last edited by QPlace; 21st February 2013 at 00:47.

  17. #12
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Calling Qt library from non-Qt C++ client

    Quote Originally Posted by QPlace View Post
    I am not using any GUI stuff, so my app is QCoreApplication and not QApplication.
    Whatever... The same applies.

    Since I moved app.exe under QThread (per your advise) it correctly enters the event loop, so QThread seems not to be the problem.
    My test was entering the event loop as well (I think) but I was getting a warning on a console about the application being created in a wrong thread if I used QThread.

    (In my current version, there are two threads. The child thread is spawned by the main thread where app.exec() is being called. Main thread calls app.exec in it' run method. The child thread instantiate the sender of signals in constructor, it is also the receiver. Child thread connects sender and itself with "connect" and calls "exec()" in its run method.)
    I don't get it. So how many threads are there in the application? Two or three? Is the application accepting signals from its own thread (check that by not creating this worker thread and create a timer object and connect its timeout signal to something that lives in the same thread as the application object)?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  18. The following user says thank you to wysota for this useful post:

    QPlace (21st February 2013)

  19. #13
    Join Date
    Jul 2007
    Posts
    121
    Thanks
    38
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Calling Qt library from non-Qt C++ client

    The "application" is a qt library that normally is loaded as a plugin. I had to call this library from the non-Qt client. This library implements a socket connection to a server. Upon receiving a message it emits a signal.
    Normal structure of the qtlibrary is:
    Qt Code:
    1. class socketImpl
    2. {
    3. ...
    4. signals:
    5. void onMessage();
    6. };
    To copy to clipboard, switch view to plain text mode 

    and

    Qt Code:
    1. class messageHandler
    2. {
    3. public:
    4. messsageHandler()
    5. {
    6. connect (&_socket, SIGNAL(onMessage()), this, SIGNAL (onMessage()));
    7. }
    8. signals:
    9. void onMessage();
    10. private:
    11. socketImpl _socket;
    12. }
    To copy to clipboard, switch view to plain text mode 

    messageHandler is also derived from the interface, but this is unimportant.

    When this plugin is loaded in the Qt-based client everything works as expected, slots are being called etc.

    Now, I need to use this library in non-Qt C++ client. For this I created two exported functions, init() and start()
    In a separate C++ file that is a part of a library I created a QThread-based (as you advised) global variable (say globalApp) that instantiates QCoreApplication and invokes .exec() on it.
    The first function, init(), starts this thread by calling globalApp.start. Next function, init() tries all sorts of things to instantiate messageHandler and connect it's signal to the slots of some class, either globalApp or another one, like a separate thread spawned from globalApp.
    This thread is totally optional, I am just trying to instantiate messageHandler class. I tried to instantiate it in the globalApp, then tried to create another thread that is spawned by globalApp to instantiate messageHandler there, but in all cases my slots that I created in globalApp or in the auxillary thread and connected them to messageHandler signals are not called.

  20. #14
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Calling Qt library from non-Qt C++ client

    So where exactly is the application object instantiated? Where is the socket created? Is this a QAbstractSocket subclass? How do you communicate with the socket?

    Let me stress this again --- all objects that are to use signals and slots need to be created in threads that are going to have an active event loop, which basically means you have to create all those objects (the application object, sockets, etc.) in the thread that is going to call QCoreApplication::exec().
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  21. The following user says thank you to wysota for this useful post:

    QPlace (21st February 2013)

  22. #15
    Join Date
    Jul 2007
    Posts
    121
    Thanks
    38
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Calling Qt library from non-Qt C++ client

    I believe that it is exactly what I am doing.

    Qt Code:
    1. #include <sstream>
    2.  
    3. // header
    4. class servicemanager : public QThread
    5. {
    6. Q_OBJECT
    7. public:
    8. servicemanager();
    9. ~servicemanager();
    10. void run() { exec(); }
    11. bool init(const char* ip, int port, const char* account );
    12.  
    13. void setAccount(const char* acct);
    14. const char* positions();
    15. public slots:
    16. void onAccountInfo(QString acct, QString what, int why);
    17. void onConnectStatus(bool stat);
    18. private:
    19. ITservice _service;
    20. QString _account;
    21. };
    22.  
    23. class ThreadedApp : public QThread {
    24. Q_OBJECT
    25. public:
    26. ThreadedApp() : QThread() { }
    27. void run();
    28. bool init(const char* ip, int port, const char* account );
    29. private:
    30. servicemanager _manager;
    31. };
    32.  
    33.  
    34. // implementation
    35. servicemanager::servicemanager() : QThread(){}
    36.  
    37. servicemanager::~servicemanager(){}
    38.  
    39. bool servicemanager::init(const char* ip, int port, const char* account )
    40. {
    41. bool res = QObject::connect(&_service, SIGNAL (onConnect(bool)), this, SLOT(onConnectStatus(bool)));
    42. res = QObject::connect(&_service, SIGNAL(onAccountInfo(QString, QString, int)), this, SLOT(onAccountInfo(QString, QString, int)));
    43. bool val = _service.connect(true);
    44. return val;
    45. }
    46.  
    47.  
    48. void servicemanager::onAccountInfo(QString acct, QString what, int why)
    49. {
    50. }
    51.  
    52. void servicemanager::onConnectStatus(bool stat)
    53. {
    54. }
    55.  
    56. void ThreadedApp::run() {
    57. int i = 1;
    58. char *argv[] = { "myapp" };
    59. QCoreApplication app(i, argv);
    60. app.exec();
    61. }
    62.  
    63. bool ThreadedApp::init(const char* ip, int port, const char* account )
    64. {
    65. _manager.start();
    66. aia::support::waitHere(1000); // wait one sec
    67. return _manager.init(ip, port, account);
    68. }
    69.  
    70. ThreadedApp app;
    71.  
    72. extern "C"
    73. {
    74. bool start()
    75. {
    76. app.start();
    77. return true;
    78. }
    79.  
    80. bool init(const char* ip, int port, const char* account )
    81. {
    82. return app.init(ip,port,account);
    83. }
    84. };
    To copy to clipboard, switch view to plain text mode 

  23. #16
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Calling Qt library from non-Qt C++ client

    Let's see...

    ThreadedApp is a global object, created when the library is loaded so it's the thread that is running the main application.

    This object contains the "servicemanager" instance so it is also created in the main application thread.

    This object in turn contains the ITservice instance you try to connect to, so it also lives in the main application thread.

    Your QCoreApplication instance is created in ThreadedApp::run() so it lives in "ThreadedApp" thread.

    So in the end your application object lives in a different thread than all the other objects. Since they do not live in a thread that runs an event loop, they won't be calling any slots as a result to any cross-thread signal they may achieve. Assuming one of those objects contains a QAbstractSocket, this socket will not receive any data either (since it relies on a running event loop as well).

    To sum it up -- your application instance is totally useless as it is the only object living in a thread containing a running event loop.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  24. The following user says thank you to wysota for this useful post:

    QPlace (21st February 2013)

  25. #17
    Join Date
    Jul 2007
    Posts
    121
    Thanks
    38
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Calling Qt library from non-Qt C++ client

    Thank you. Your help is invaluable. I made a slight( )change and it works now.

  26. #18
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Calling Qt library from non-Qt C++ client

    Out of curiosity... does the main application have some kind of event loop?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  27. #19
    Join Date
    Jul 2007
    Posts
    121
    Thanks
    38
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Calling Qt library from non-Qt C++ client

    Yes, the C++ client is a non Qt C++ app, in my test case I am using autogenerated atl project with mainwindow, in my real case I am going to use excel c++ addin.

  28. #20
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Calling Qt library from non-Qt C++ client

    Can't you just provide means to plugins from within the main application to process their events periodically? There you could just call QCoreApplication::processEvents() without any need for additional threads and similar problems.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Similar Threads

  1. Calling a .NET library (.dll) from a Qt application
    By magpielover in forum Qt Programming
    Replies: 0
    Last Post: 11th January 2012, 15:21
  2. Replies: 2
    Last Post: 6th May 2011, 14:20
  3. Replies: 2
    Last Post: 19th February 2011, 11:26
  4. Client-Client communication
    By zgulser in forum Newbie
    Replies: 0
    Last Post: 2nd December 2010, 08:07
  5. Calling a library in Symbian C++ using Qt
    By zhengping in forum Newbie
    Replies: 2
    Last Post: 22nd June 2010, 02:04

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.