wxAutomationObject CoInitialize has not been called error in wxThread Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
sw
Knows some wx things
Knows some wx things
Posts: 47
Joined: Sat Mar 16, 2019 8:09 pm

wxAutomationObject CoInitialize has not been called error in wxThread

Post by sw » Mon Aug 24, 2020 9:34 am

When using a wxAutomationObject in a wxThread it fails with the following error: "(caller: 7503540B) ReturnHr(1) tid(c79c) 800401F0 CoInitialize has not been called." This is coming from the combase.dll. This happens with GetInstance() and CreateInstance()

However, running the same code on the main thread does not produce any errors and it works as expected.

In my testing, I've found that calling GetInstance() can be quite slow so I put that code in a wxThread so as to not lock up the main thread.

I am interfacing with Outlook through wxAutomationObject's. I don't see any gotcha's in the docs about using wxAutomationObject in a wxThread, unless there is some sort of Microsoft COM limitation?

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2675
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxAutomationObject CoInitialize has not been called error in wxThread

Post by PB » Mon Aug 24, 2020 10:41 am

Well, I have no experience with this but the error message seems to be pretty clear.

wxWidgets initialize the COM in the main thread (using wxOleInitialize()) but you need to do that for the threads you create (and probably call wxOleUninitialize() on the thread deletion). See https://docs.microsoft.com/en-us/window ... initialize

Did you do that or something along those lines(e.g., ::CoInitializeEx())?

sw
Knows some wx things
Knows some wx things
Posts: 47
Joined: Sat Mar 16, 2019 8:09 pm

Re: wxAutomationObject CoInitialize has not been called error in wxThread

Post by sw » Mon Aug 24, 2020 12:50 pm

Oh, that makes sense. I didn't know wxWidgets would initialize it for you.

Thus I have added wxOleInitialize() and wxOleUnitialize() in my wxThread class constructor and destructor, respectively, and I still get the same error.

Calling the actual Windows functions (OleInitialize() and OleUninitialize()) results in the same error. Although when calling the Windows API I see the result from ::OleInitialize() is S_FALSE which means that OLE is initialized already? #-o

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2675
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxAutomationObject CoInitialize has not been called error in wxThread

Post by PB » Mon Aug 24, 2020 1:16 pm

Sorry, I have no idea about this, I have long forgotten the little I knew about COM.
This naive approach seems to work, but I am sure I am missing some gotchas so I would be wary to use it

Code: Select all

#include <wx/wx.h>
#include <wx/msw/ole/automtn.h>
#include <wx/msw/ole/oleutils.h>
#include <wx/thread.h>

class MyWorkerThread : public wxThread
{
public:
    MyWorkerThread() : wxThread(wxTHREAD_JOINABLE)
    {}

protected:
    ExitCode Entry() override
    {
        wxAutomationObject application;

        //wxOleInitialize();
        ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
        if ( !application.GetInstance("Outlook.Application") )
            wxLogError("Could not start automated application.");
        else
            wxLogMessage("Outlook launched.");

        while ( !TestDestroy() )
        {
            wxMilliSleep(250);
        }

        //wxOleUninitialize();
        ::CoUninitialize();
        return static_cast<wxThread::ExitCode>(nullptr);
    }
};

class MyFrame: public wxFrame
{
public:
    MyFrame() : wxFrame (NULL, wxID_ANY, "Test")
    {
        wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);

        wxButton* button = new wxButton(this, wxID_ANY, "Start thread");
        mainSizer->Add(button, wxSizerFlags().TripleBorder());
        button->Bind(wxEVT_BUTTON, &MyFrame::OnStartThread, this);

        SetSizerAndFit(mainSizer);
    }
    ~MyFrame()
    {
        StopThread();
    }

private:
    MyWorkerThread*  m_thread = nullptr;

    void OnStartThread(wxCommandEvent&)
    {
        StopThread();

        m_thread = new MyWorkerThread();
        if ( m_thread->Run() != wxTHREAD_NO_ERROR )
        {
            delete m_thread;
            m_thread = nullptr;
            wxLogError(_("Could not create the thread."));
        }
    }

    void StopThread()
    {
        if ( m_thread )
        {
            m_thread->Delete();
            delete m_thread;
            m_thread = nullptr;
        }
    }
};

class MyApp : public wxApp
{
public:
    bool OnInit()
    {
        (new MyFrame())->Show();
        return true;
    }
}; wxIMPLEMENT_APP(MyApp);
Anyway, I'd rather not "advise" you on this any more, it would blind leading the blind.

User avatar
doublemax
Moderator
Moderator
Posts: 15283
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxAutomationObject CoInitialize has not been called error in wxThread

Post by doublemax » Mon Aug 24, 2020 3:53 pm

in my wxThread class constructor and destructor, respectively,
I believe at least the ctor is not called in the new thread context. Try moving the ::CoInitializeXXX calls to Entry() and Exit().
Use the source, Luke!

sw
Knows some wx things
Knows some wx things
Posts: 47
Joined: Sat Mar 16, 2019 8:09 pm

Re: wxAutomationObject CoInitialize has not been called error in wxThread

Post by sw » Mon Aug 24, 2020 9:25 pm

@PB Thank you for your assistance though :)

@doublemax It was indeed the context! I don't understand why the constructor and Entry() run in a seemingly different contexts, but calling wxOleInitialize() in Entry() did not throw any errors and worked as expected. I presume you meant OnExit()? And in OnExit() I call wxOleUnitialize()

Post Reply