windows-nt/Source/XPSP1/NT/windows/oleacc/msaatext/msaaadapter.cpp
2020-09-26 16:20:57 +08:00

263 lines
6.4 KiB
C++

// MSAAAdapter.cpp : Implementation of CAccServerDocMgr
#include "stdafx.h"
#include "MSAAText.h"
#include "MSAAAdapter.h"
#define INITGUID
#include <msctfx.h>
#include "MSAAStore.h"
// - in AnchorWrap.cpp
HRESULT WrapACPToAnchor( ITextStoreACP * pDocAcp, ITextStoreAnchor ** ppDocAnchor );
CAccServerDocMgr::CAccServerDocMgr()
: m_pAccStore( NULL )
{
IMETHOD( CAccServerDocMgr );
}
CAccServerDocMgr::~CAccServerDocMgr()
{
IMETHOD( ~CAccServerDocMgr );
if( m_pAccStore )
{
m_pAccStore->Release();
}
}
BOOL CheckForWrapper( ITextStoreAnchor ** ppDoc )
{
// Is this a cloneable wrapper? If not, need to wrap it...
IClonableWrapper * pClonableWrapper = NULL;
HRESULT hr = (*ppDoc)->QueryInterface( IID_IClonableWrapper, (void **) & pClonableWrapper );
if( hr == S_OK && pClonableWrapper )
{
// It already supports IClonableWrapper - nothing else to do...
pClonableWrapper->Release();
return TRUE;
}
// Need to use doc wrapper to get clonable (multi-client) support
IDocWrap * pDocWrap = NULL;
hr = CoCreateInstance( CLSID_DocWrap, NULL, CLSCTX_SERVER, IID_IDocWrap, (void **) & pDocWrap );
if( hr != S_OK || ! pDocWrap )
return FALSE;
hr = pDocWrap->SetDoc( IID_ITextStoreAnchor, *ppDoc );
if( hr != S_OK )
{
pDocWrap->Release();
return FALSE;
}
ITextStoreAnchor * pNewDoc = NULL;
hr = pDocWrap->GetWrappedDoc( IID_ITextStoreAnchor, (IUnknown **) & pNewDoc );
pDocWrap->Release();
if( hr != S_OK || ! pNewDoc )
return FALSE;
// This time round, QI should work (since we're talking to a wrapper)...
pClonableWrapper = NULL;
hr = pNewDoc->QueryInterface( IID_IClonableWrapper, (void **) & pClonableWrapper );
if( hr != S_OK || ! pClonableWrapper )
{
pNewDoc->Release();
return FALSE;
}
// Yup, it worked - replace the input doc with the new wrapped doc...
pClonableWrapper->Release();
(*ppDoc)->Release();
*ppDoc = pNewDoc;
return TRUE;
}
HRESULT STDMETHODCALLTYPE CAccServerDocMgr::NewDocument (
REFIID riid,
IUnknown * punk
)
{
IMETHOD( NewDocument );
// Check for known IIDs...
CComPtr<ITextStoreAnchor> pDoc;
if( riid == IID_ITextStoreAnchor || riid == IID_ITfTextStoreAnchor )
{
pDoc = (ITextStoreAnchor *) punk;
}
else if( riid == IID_ITextStoreACP || riid == IID_ITfTextStoreACP )
{
TraceParam( TEXT("Got ACP doc, but ACP->Anchor wrapping not currently supported") );
return E_NOTIMPL;
/*
// We don't currently support ACP- interfaces directly - cicero always gives us
// Anchor interfaces, wrapping ACPs if necesary.
HRESULT hr = WrapACPToAnchor( static_cast<ITextStoreACP *>( punk ), & pDoc );
if( hr != S_OK )
return hr;
*/
}
else
{
TraceParam( TEXT("Got unknown interface - wasn't ITextStoreAnchor/ITfTextStoreAnchor") );
return E_NOINTERFACE;
}
// Wrap the doc if necessary, to get multi-client support (via IClonableWrapper)...
if( ! CheckForWrapper( & pDoc.p ) )
{
return E_FAIL;
}
if( ! m_pAccStore )
{
m_pAccStore = NULL;
HRESULT hr = CoCreateInstance( CLSID_AccStore, NULL, CLSCTX_LOCAL_SERVER, IID_IAccStore, (void **) & m_pAccStore );
if( ! m_pAccStore )
{
TraceErrorHR( hr, TEXT("CoCreate(AccStore)") );
return hr;
}
}
// TODO - what IID here?
HRESULT hr = m_pAccStore->Register( IID_ITextStoreAnchor, pDoc.p );
if( hr != S_OK )
{
TraceErrorHR( hr, TEXT("m_pAccStore->Register()") );
return hr;
}
IUnknown * pCanonicalUnk = NULL;
hr = punk->QueryInterface( IID_IUnknown, (void **) & pCanonicalUnk );
if( hr == S_OK && pCanonicalUnk != NULL )
{
DocAssoc * pDocAssoc = new DocAssoc;
if ( !pDocAssoc )
{
return E_OUTOFMEMORY;
}
pDocAssoc->m_pdocAnchor = pDoc;
pDocAssoc->m_pdocOrig = pCanonicalUnk;
m_Docs.AddToHead( pDocAssoc );
}
else
{
AssertMsg( FALSE, TEXT("QI(IUnknown) failed") );
return hr;
}
pDoc.p->AddRef();
return S_OK;
}
HRESULT STDMETHODCALLTYPE CAccServerDocMgr::RevokeDocument (
IUnknown * punk
)
{
IMETHOD( RevokeDocument );
if ( !punk )
return E_INVALIDARG;
// Get the canonical IUnknown for comparison purposes...
IUnknown * pCanonicalUnk = NULL;
if( punk->QueryInterface( IID_IUnknown, (void **) & pCanonicalUnk ) != S_OK || pCanonicalUnk == NULL )
{
return E_FAIL;
}
// Do we recognise this doc?
DocAssoc * pDocAssoc = NULL;
for( Iter_dl< DocAssoc > i ( m_Docs ) ; ! i.AtEnd() ; i++ )
{
if( i->m_pdocOrig == pCanonicalUnk )
{
pDocAssoc = i;
break;
}
}
pCanonicalUnk->Release();
if( ! pDocAssoc )
{
// Not found
return E_INVALIDARG;
}
// Unregister with the store...
HRESULT hr = m_pAccStore->Unregister( pDocAssoc->m_pdocAnchor );
if( hr != S_OK )
{
TraceErrorHR( hr, TEXT("m_pAccStore->Unregister()") );
}
// Try calling IInternalDocWrap::NotifyRevoke() to tell the DocWrapper that the doc is
// going away. (It will forward this to any interested clients.)
IInternalDocWrap * pInternalDocWrap = NULL;
hr = pDocAssoc->m_pdocAnchor->QueryInterface( IID_IInternalDocWrap, (void **) & pInternalDocWrap );
if( hr == S_OK && pInternalDocWrap )
{
pInternalDocWrap->NotifyRevoke();
pInternalDocWrap->Release();
}
else
{
TraceErrorHR( hr, TEXT("pdocAnchor didn't support IInternalDocWrap - was it wrapped properly?") );
}
// Remove from internal list...
m_Docs.remove( pDocAssoc );
pDocAssoc->m_pdocOrig->Release();
pDocAssoc->m_pdocAnchor->Release();
delete pDocAssoc;
// Done.
return hr;
}
HRESULT STDMETHODCALLTYPE CAccServerDocMgr::OnDocumentFocus (
IUnknown * punk
)
{
IMETHOD( OnDocumentFocus );
if( ! m_pAccStore )
{
m_pAccStore = NULL;
HRESULT hr = CoCreateInstance( CLSID_AccStore, NULL, CLSCTX_LOCAL_SERVER, IID_IAccStore, (void **) & m_pAccStore );
if( ! m_pAccStore )
{
TraceErrorHR( hr, TEXT("CoCreate(AccStore)") );
return hr;
}
}
return m_pAccStore->OnDocumentFocus( punk );
}