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?
wxAutomationObject CoInitialize has not been called error in wxThread Topic is solved
Re: wxAutomationObject CoInitialize has not been called error in wxThread
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())?
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())?
Re: wxAutomationObject CoInitialize has not been called error in wxThread
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?
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?
Re: wxAutomationObject CoInitialize has not been called error in wxThread
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
Anyway, I'd rather not "advise" you on this any more, it would blind leading the blind.
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);
Re: wxAutomationObject CoInitialize has not been called error in wxThread
I believe at least the ctor is not called in the new thread context. Try moving the ::CoInitializeXXX calls to Entry() and Exit().in my wxThread class constructor and destructor, respectively,
Use the source, Luke!
Re: wxAutomationObject CoInitialize has not been called error in wxThread
@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()
@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()