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.
Note
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 );
}
};