You have to marshal the IServiceProvider interface from your main thread to your background thread.
In your
SetSite
call (which is guaranteed to be called on the main UI thread), marshal the
IServiceProvider
interface into a shared stream (
IStream
)
object using
CoMarshalInterThreadInterfaceInStream
. You’ll need to make sure that this shared object can be accessed from both threads. In your background thread, when you need to get at the
IServiceProvider
, call
CoGetInterfaceAndReleaseStream
to get back a proxied
IServiceProvider
that works for the calling thread. Note that you can call this only once, so cache the interface that you get back. You can then call through this interface to
QueryService
. See the example code below:
class
CMyPackage : public IVsPacakge
{
private
:
CComPtr< IStream > m_pSPStream; // Used to marshal IServiceProvider between threads
CComPtr< IServiceProvider > m_pBackgroundSP; // IServiceProvider proxy for the background thread
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
void **ppvObj // [out] Interface pointer of requested service (NULL on error)
{
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 );
}
};