Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

"CoInitialize has not been called." warning



  • After migrating from Qt 5.13.2 to 5.14.0, our unit tests suddenly started spitting out the following warning:

    qt.network.monitor: Failed to subscribe to network connectivity events: "CoInitialize has not been called."
    qt.network.monitor: failed to start network status monitoring
    

    The moment this happens, the top of the call stack is as follows:

    Qt5Networkd.dll!QNetworkListManagerEvents::start() Line 594	C++
    Qt5Networkd.dll!QNetworkStatusMonitorPrivate::start() Line 652	C++
    Qt5Networkd.dll!QNetworkStatusMonitor::start() Line 677	C++
    Qt5Networkd.dll!QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest & originalReq, QIODevice * outgoingData) Line 1479	C++
    Qt5Networkd.dll!QNetworkAccessManager::post(const QNetworkRequest & request, QIODevice * data) Line 893	C++
    Qt5Networkd.dll!QNetworkAccessManager::post(const QNetworkRequest & request, QHttpMultiPart * multiPart) Line 930	C++
    OurOwn.dll!OurOwnClass::someMethod(...)
    

    so this happens when we call QNetworkAccessManager::post from inside OurOwnClass::someMethod().

    Any ideas on what has changed between 5.13.2 and 5.14.0 that triggers this warning, and on how to fix it, are welcome!



  • @Bart_Vandewoestyne said in "CoInitialize has not been called." warning:

    Is there an official bug report for that specific bug? I've searched https://bugreports.qt.io/ but cannot find it :-( Would be nice to know what commit(s) fix(es) it, so we can apply a patch to our local 5.15.0 vendor branch.

    Bugreport: https://bugreports.qt.io/browse/QTBUG-84031
    Patch: https://codereview.qt-project.org/c/qt/qtbase/+/305169

    Thanks to @manordheim !
    I consider this issue fixed. All I must do is wait for 5.15.1 and test again :-)



  • It seems that there are some new internal classes which use COM APIs in Windows.
    Have you ever moved QNetworkAccessManager to another thread?
    I think this is probably the reason because CoInitialize needs to be called in every thread calling COM APIs.



  • I did come across https://bugreports.qt.io/browse/QTBUG-84031 in my search, and the commit that fixes it: https://github.com/qt/qtbase/commit/f1f0aa4a3a7d364b5110122a8f77079a7742c4e9
    Apparently, this fix will be included in Qt 5.15.1 (to be released in August 2020), so I'll definitely try with that version to see if the warning goes away.

    In the meanwhile, I'll double-check our code tomorrow to see if we are moving a QNetworkAccessManager object to another thread somewhere.



  • Hello! With 5.14.0 the QNetworkStatusMonitor was added. Without knowing more (and assuming it was not moved across threads); was QNetworkAccessManager::post called from a different thread than it was created in? Otherwise I'm not sure what would cause it from looking at the stacktrace and the code. But if that's the case then that's not really supported: Since QNetworkAccessManager is based on QObject, it can only be used from the thread it belongs to.



  • @Bonnie Yes, apparently, there is one place in our code where the QNetworkAccessManager object is moved to another thread. However, to the best of my knowledge, we are only using our QNetworkAccessManager object in the thread it belongs to.

    You write that CoInitialize needs to be called in every thread calling COM APIs... Do you have any idea how we can make sure that this is the case after moving our QNetworkAccessManager object to a different thread?



  • @Bart_Vandewoestyne
    You could call the necessary CoInitialize() immediately before/after moving your QNetworkAccessManager object to a different thread (call from the destination thread)?



  • @manordheim, I am still fighting with this issue, but probably getting closer to nailing it down. Here's the situation: we have some kind of wrapper class, let's call it Wrapper, that has a member of type QNetworkAccessManager and of QThread:

    class Wrapper :: public QObject
    {
    ...
    private:
        QNetworkAccessManager mvNetworkAccessManager;
        QThread mvThread;
    }
    

    Inside Wrapper's constructor, we move mvNetworkAccessManager to another thread that we then start:

    Wrapper::Wrapper()
        : mvNetworkAccessManager(this)
    {
        ... some logging with QThread::currentThreadId() to print the thread ID ...
    
        this->moveToThread(&mvThread);
        mvThread.start();
    }
    

    The QNetworkAccessManager::post method gets called from a member function of the Wrapper class:

    void Wrapper::doThePost()
    {
        ...
        ... some logging with QThread::currentThreadId() to print the thread ID ...
        reply = mvNetworkAccessManager.post(... stuff ...)
        ...
    }
    

    The currentThreadId() that gets printed from the constructor is different from the currentThreadId() that gets printed from doThePost(). Am I right if I say that this is the problem?

    To be able to call CoInitializeEx from the thread where the post() method is called, I changed the constructor code as follows:

        this->moveToThread(&mvThread);
        connect(&mvThread, &QThread::started, this, &Wrapper::mpHandleThreadStarted);
        connect(&mvThread, &QThread::finished, this, &Wrapper::mpHandleThreadFinished);
        mvThread.start();
    

    with

    void ICNetworkAccessManager::mpHandleThreadStarted()
    {
        ... some logging with QThread::currentThreadId() to print the thread ID ...
    
        HRESULT hr;
        hr = CoInitializeEx(0, COINIT_MULTITHREADED);
        if (FAILED(hr))
        {
           ... print failure ...
        }
        else
        {
            ... print success ...
        }
    }
    

    and

    void ICNetworkAccessManager::mpHandleThreadFinished()
    {
        ... some logging with QThread::currentThreadId() to print the thread ID ...
        
        CoUninitialize();
    }
    

    From the logging in the mpHandleThreadStarted method, I can see that I am calling CoInitializeEx from the same thread as the one where I call my QNetworkAccessManager::post. I also don't see the "CoInitialize has not been called " warning anymore, but unfortunately, the new warning (occurring at exactly the same location, when calling post()) is now

    qt.network.monitor: Failed to subscribe to network connectivity events: "The application called an interface that was marshalled for a different thread."
    

    Before that warning, I also see

    onecore\com\combase\dcomrem\stdid.cxx(725)\combase.dll!754896A6: (caller: 754B13B1) ReturnHr(1) tid(4490) 8001010E The application called an interface that was marshalled for a different thread.
    onecore\com\combase\dcomrem\stdid.cxx(725)\combase.dll!754896A6: (caller: 754B13B1) ReturnHr(2) tid(4490) 8001010E The application called an interface that was marshalled for a different thread.
    onecore\com\combase\dcomrem\stdid.cxx(725)\combase.dll!754896A6: (caller: 754B13B1) ReturnHr(3) tid(4490) 8001010E The application called an interface that was marshalled for a different thread.
    onecore\com\combase\dcomrem\stdid.cxx(725)\combase.dll!754896A6: (caller: 754B13B1) ReturnHr(4) tid(4490) 8001010E The application called an interface that was marshalled for a different thread.
    

    and so this is again where I'm stuck. Any ideas/suggestions on how to proceed are very welcome!



  • @manordheim said in "CoInitialize has not been called." warning:

    [...] But if that's the case then that's not really supported: Since QNetworkAccessManager is based on QObject, it can only be used from the thread it belongs to.

    Just to make sure I understand the Qt documentation right: what exactly do they mean by "it can only be used from the thread it belongs to". Do they mean "the thread it was created" or "the thread it was moved to"? I assume the second, but just need confirmation ;-)


  • Qt Champions 2019

    @Bart_Vandewoestyne said in "CoInitialize has not been called." warning:

    "the thread it was created" or "the thread it was moved to"?

    both



  • @jsulm said in "CoInitialize has not been called." warning:

    both

    I'm afraid I cannot follow here... This is my understanding: if the object is created in thread A, and is not moved yet to a thread B, then it 'belongs to' thread A and all its slots will run on thread A. Once we move the object to thread B (using moveToThread), then it 'belongs to' thread B and from that moment on all its slots will run on thread B (if I understand things correctly, please correct me if I'm wrong).

    Is that why you replied 'both'? Or am I fundamentally misunderstanding something here?



  • Using Qt 5.15.0, I was able to create the following minimal example that reproduces the problem:

        QNetworkRequest request;
        QHttpMultiPart* multiPart = new QHttpMultiPart();
        QNetworkAccessManager mgr;
        QThread thread;
    
        QObject::connect( &thread, &QThread::started,
                         [&]() { mgr.post(request, multiPart); } );
    
        mgr.moveToThread(&thread);
        thread.start();
    
        thread.quit();
        thread.wait();
    

    and thus triggers the warning

    qt.network.monitor: Failed to subscribe to network connectivity events: "CoInitialize has not been called."
    qt.network.monitor: failed to start network status monitoring
    

    I think my two questions are now:

    1. Is this a bug in Qt? Shouldn't the internal network monitoring code call CoInitialize at the right place?
    2. If it is not a bug, then how to make the warning go away?


  • @Bart_Vandewoestyne said in "CoInitialize has not been called." warning:

    Is this a bug in Qt? Shouldn't the internal network monitoring code call CoInitialize at the right place?

    I think it is.
    And we all know there will be a fix in 5.15.1, don't we?
    Unfortunately it seems to be delayed.
    Just hope it could be released ASAP...



  • @Bart_Vandewoestyne Yeah, this specific bug was fixed in 5.15.1. But more recently the built-in connection status pre-check was dropped entirely from 5.15.1 (and 6.0).



  • @manordheim said in "CoInitialize has not been called." warning:

    @Bart_Vandewoestyne Yeah, this specific bug was fixed in 5.15.1.

    Is there an official bug report for that specific bug? I've searched https://bugreports.qt.io/ but cannot find it :-( Would be nice to know what commit(s) fix(es) it, so we can apply a patch to our local 5.15.0 vendor branch.



  • @Bart_Vandewoestyne said in "CoInitialize has not been called." warning:

    Is there an official bug report for that specific bug? I've searched https://bugreports.qt.io/ but cannot find it :-( Would be nice to know what commit(s) fix(es) it, so we can apply a patch to our local 5.15.0 vendor branch.

    Bugreport: https://bugreports.qt.io/browse/QTBUG-84031
    Patch: https://codereview.qt-project.org/c/qt/qtbase/+/305169

    Thanks to @manordheim !
    I consider this issue fixed. All I must do is wait for 5.15.1 and test again :-)



  • @Bart_Vandewoestyne said in "CoInitialize has not been called." warning:

    [...] All I must do is wait for 5.15.1 and test again :-)

    For the record: Qt 5.15.1 is available from http://download.qt.io/official_releases/qt/5.15/5.15.1/.
    I tested again using this version, and the qt.network.monitor warnings no longer appear, so problem solved.

    Thanks!


Log in to reply