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