How to: Get a Service from a Background Thread (C++)

 

Services cannot be obtained by means of IServiceProvider.QueryService from a background thread. If you use QueryService to get a service on the main thread, and then try to use the service on a background thread, it also will fail.

To get a service from a background thread, use CoMarshalInterThreadInterfaceInStream in the IVsPackage.SetSite method to marshal the service provider into a stream on the main thread. You then can unmarshal the service provider on a background thread and use it to get the service. You can unmarshal only once, so cache the interface that you get back.

System_CAPS_noteNote

Managed code automatically marshals interfaces between threads, so getting a service from a background thread does not require special code.

Example

The following code marshals a service provider in the main thread and provides a QueryServiceFromBackgroundThread method to unmarshal the service provider to get a service from a background thread.

class CMyPackage : public IVsPackage
{
private:
    // Used to marshal IServiceProvider between threads
    CComPtr< IStream > m_pSPStream;
    // IServiceProvider proxy for the background thread
    CComPtr< IServiceProvider > m_pBackgroundSP;

public:
    HRESULT SetSite( IServiceProvider* pSP )
    {
        // Marshal the service provider into a stream so that
        // the background thread can retrieve it later
        CoMarshalInterThreadInterfaceInStream(
            IID_IServiceProvider, pSP, &m_pSPStream);

        //... do the rest of your initialization
    }

    // Call this when your background thread needs to call QueryService
    // The first time through, it unmarshals the interface stored 
    HRESULT QueryServiceFromBackgroundThread(
        REFGUID rsid,        // [in] Service ID
        REFIID riid,         // [in] Interface ID
        // [out] Interface pointer of requested service (NULL on error)
        void **ppvObj
    {
        if( !m_pBackgroundSP )
        {
            if( !m_pSPStream )
            {
                return E_UNEXPECTED;
            }

            HRESULT hr = CoGetInterfaceAndReleaseStream( 
                m_pSPStream, IID_IServiceProvider, 
                (void **)&m_pBackgroundSP );
            if( FAILED(hr) )
            {
                return hr;
            }

            // The CoGetInterfaceAndReleaseStream has already 
            // destroyed the stream.  To avoid double-freeing, 
            // the smart wrapper needs to be detached.
            m_pSPStream.Detach();
        }

        return m_pBackgroundSP->QueryService( rsid, riid, ppvObj );
    }
};
Show: