aurel
aurel

Reputation: 1137

Why COM doesn't work in a new thread?

My problems started after converting my VS2003 project to VS2008. Solution contains 3 projects. Projects are DLL's. There were A LOT of compilation errors, then some linker errors... Well, I fought them off. Now it just simply doesn't work ;)

So, one of this DLL's is suppoused to communicate with Word by COM.

Word::_ApplicationPtr d_pApp;
Word::_DocumentPtr d_pDoc;

void MSWord2003::init()
{
    free();
    HRESULT hr;
    CLSID clsid;
    CLSIDFromProgID(L"Word.Application", &clsid);  

     // Get an interface to the running instance, if any..
    IUnknown *pUnk;

    hr = GetActiveObject(clsid, NULL, (IUnknown**)&pUnk);
    if(hr!=S_OK)
        throw MSWord::MSWordException("Nie znaleziono działającej aplikacji MSWord.");

    IDispatch* d_pDispApp;
    hr = pUnk->QueryInterface(IID_IDispatch, (void**)&d_pDispApp);
    if(hr!=S_OK)
        throw MSWord::MSWordException("Nie udało się połączyć z aplikacją MSWord.");

    pUnk->Release();
    pUnk = 0;

    d_pApp = d_pDispApp;
    d_pDoc = d_pApp->ActiveDocument;

    d_pDispApp->AddRef();   


    d_currIdx = -1;

    paragraphsCount = d_pDoc->GetParagraphs()->Count;
    footnotesCount = d_pDoc->GetFootnotes()->Count;
    endnotesCount = d_pDoc->GetEndnotes()->Count;
}

void MSWord2003::free()
{
    if(d_pApp!=0)
    {
        d_pApp->Release();
        d_pApp=0;
    }
}

This code works on VS2003 (and different machine, I don't have VS2003 on my computer) while in VS2008 it works only if it is called by main thread. When called by a new thread (wich is initialized by CoInitialize) d_pApp is not initialized properly - its ptr shows 0.

While debugging I reached code in comip.h:

template<typename _InterfacePtr> HRESULT _QueryInterface(_InterfacePtr p) throw()
    {
        HRESULT hr;

        // Can't QI NULL
        //
        if (p != NULL) {
            // Query for this interface
            //
            Interface* pInterface;
            hr = p->QueryInterface(GetIID(), reinterpret_cast<void**>(&pInterface));

            // Save the interface without AddRef()ing.
            //
            Attach(SUCCEEDED(hr)? pInterface: NULL);
        }
        else {
            operator=(static_cast<Interface*>(NULL));
            hr = E_NOINTERFACE;
        }

        return hr;
    }

In a new thread, QueryInterface returns E_NOINTERFACE, although GetIID() returns the same thing for both threads. And that is where I got stuck - I have no idea, what causes this behaviour...

Upvotes: 1

Views: 419

Answers (1)

Soonts
Soonts

Reputation: 21936

IMO you should initialize COM not with CoInitialize, but with CoInitializeEx, specifying COINIT_MULTITHREADED. Otherwise you'll have separate single-threaded COM apartment for every thread.

Upvotes: 2

Related Questions