// MSAAStore.cpp : Implementation of CAccStore #include "stdafx.h" #include "MSAAText.h" #include "MSAAStore.h" #include #include #include using namespace std; #include #include #define ARRAYSIZE( a ) (sizeof(a)/sizeof(a[0])) CAccStore * m_pTheStore = NULL; POINT ptListOffset; POINT ptDumpOffset; BOOL fGotSize = FALSE; #ifdef DBG BOOL_PTR CALLBACK DialogProc ( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { return m_pTheStore->DialogProc ( hwndDlg, uMsg, wParam, lParam ); } BOOL_PTR CAccStore::DialogProc ( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch( uMsg ) { case WM_INITDIALOG: { RECT rcWnd; GetClientRect( hwndDlg, & rcWnd ); RECT rcList; GetWindowRect( GetDlgItem( hwndDlg, IDC_LIST ), & rcList ); MapWindowPoints( NULL, hwndDlg, (POINT *) & rcList, 2 ); ptListOffset.x = rcWnd.right - ( rcList.right - rcList.left ); ptListOffset.y = rcWnd.bottom - ( rcList.bottom - rcList.top ); RECT rcDump; GetWindowRect( GetDlgItem( hwndDlg, ID_DUMP ), & rcDump ); MapWindowPoints( NULL, hwndDlg, (POINT *) & rcDump, 2 ); ptDumpOffset.x = rcWnd.right - rcDump.left; ptDumpOffset.y = rcWnd.bottom - rcDump.top; fGotSize = TRUE; break; } case WM_COMMAND: { if( LOWORD( wParam ) == ID_DUMP ) { Assert( m_pTheStore ); DumpInfo(); break; } break; } case WM_SIZE: { if( wParam != SIZE_MINIMIZED && fGotSize ) { int width = LOWORD( lParam ); int height = HIWORD( lParam ); SetWindowPos( GetDlgItem( hwndDlg, IDC_LIST ), NULL, 0, 0, width - ptListOffset.x, height - ptListOffset.y, SWP_NOMOVE | SWP_NOZORDER ); SetWindowPos( GetDlgItem( hwndDlg, ID_DUMP ), NULL, width - ptDumpOffset.x, height - ptDumpOffset.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); } break; } } return FALSE; } #endif ///////////////////////////////////////////////////////////////////////////// // CAccStore CAccStore::CAccStore() : m_hwndDlg(NULL), m_hList(NULL), m_punkFocused(NULL), m_pCtl(NULL), m_hInit(NULL) { IMETHOD( CAccStore ); Assert( m_pTheStore == NULL ); m_pTheStore = this; HRESULT hr; hr = CoCreateInstance(CLSID_MSAAControl, NULL, CLSCTX_INPROC_SERVER, IID_ITfMSAAControl, (void**)&m_pCtl); if ( hr != S_OK ) { Log( TSTR() << TEXT("CoCreateInstance failed for CLSID_MSAAControl hr=") << WriteHex(hr) ); } else { hr = m_pCtl->SystemEnableMSAA(); if ( hr != S_OK ) Log( TSTR() << TEXT("SystemEnableMSAA failed hr=") << WriteHex(hr) ); } // this lets someone in another procces se if the store is up m_hInit = CreateEvent( NULL, FALSE, TRUE, TEXT("MSAA_STORE_EVENT") ); #ifdef DBG CRegKey crkShowDialog; DWORD dwShowDialog = 0; if ( ( crkShowDialog.Open(HKEY_CURRENT_USER, TEXT("Control Panel\\Accessibility"), KEY_READ) == ERROR_SUCCESS ) && ( crkShowDialog.QueryValue( dwShowDialog, TEXT("ShowDialog") ) == ERROR_SUCCESS ) && ( dwShowDialog ) ) { m_ShowDialog = true; } else { m_ShowDialog = false; } if ( m_ShowDialog ) { m_hwndDlg = CreateDialog( _Module.GetModuleInstance(), MAKEINTRESOURCE( IDD_MAIN ), NULL, ::DialogProc ); m_hList = GetDlgItem( m_hwndDlg, IDC_LIST ); Log( TEXT("*** CAccStore ctor ***") ); if ( m_pCtl == NULL ) Log( TEXT("m_pCtl is null") ); } #endif } CAccStore::~CAccStore() { IMETHOD( ~CAccStore ); EraseDeadDocuments(); if ( m_punkFocused ) m_punkFocused->Release(); if ( m_pCtl ) { m_pCtl->SystemDisableMSAA(); m_pCtl->Release(); } if ( m_hInit ) CloseHandle( m_hInit ); m_pTheStore = NULL; Log( TEXT("*** CAccStore dtor ***") ); #ifdef DBG if ( m_ShowDialog ) { EndDialog( m_hwndDlg, TRUE ); } #endif } HRESULT STDMETHODCALLTYPE CAccStore::Register ( REFIID riid, IUnknown * punk ) { IMETHOD( Register ); EraseDeadDocuments(); if( riid != IID_ITextStoreAnchor ) { Log( TEXT("Register - unknown IID") ); return E_NOINTERFACE; } // Get the canonical IUnknown - we use this to compare against the interface // passed to Unregister. // Note that this is from the original interface peassed in, not a wrapped // version... IUnknown * pCanonicalUnk = NULL; HRESULT hr = punk->QueryInterface( IID_IUnknown, (void **) & pCanonicalUnk ); if( hr != S_OK || ! pCanonicalUnk ) { Log( TEXT("QueryInterface failed") ); return E_FAIL; } // Now check that the doc pointer is a clonable wrapper - if not, // wrap it using DocWrap. We need a clonable wrapper so we can hand // out individual 'head' interfaces to multiple clients. ITextStoreAnchor * pDoc = reinterpret_cast< ITextStoreAnchor * >( punk ); pDoc->AddRef(); IClonableWrapper * pClonableWrapper = NULL; hr = pDoc->QueryInterface( IID_IClonableWrapper, (void **) & pClonableWrapper ); if( hr != S_OK || ! pClonableWrapper ) { // Uh-oh - we were supposed to be given a doc that (a) supports IDocAnchor, and (b) // supports IClonableWrapper (so is usable by multiple clients). // return failure... TraceDebugHR( hr, TEXT( "QueryInterface for IID_IClonableWrapper failed") ); pDoc->Release(); pCanonicalUnk->Release(); return E_FAIL; } // Add info to list... m_DocList.push_back( new DocInfo(pCanonicalUnk, pDoc, pClonableWrapper) ); Log( TSTR() << TEXT("Register ") << WriteHex(pCanonicalUnk) << TEXT(", ") << WriteHex(pDoc) << TEXT(", ") << WriteHex(pClonableWrapper) ); DumpInfo( m_DocList.back() ); return S_OK; } HRESULT STDMETHODCALLTYPE CAccStore::Unregister ( IUnknown * punk ) { IMETHOD( Unregister ); Log( TEXT("Unregister") ); IUnknown * pCanonicalUnk = NULL; HRESULT hr = punk->QueryInterface( IID_IUnknown, (void **) & pCanonicalUnk ); if( hr != S_OK || ! pCanonicalUnk ) { return E_FAIL; } DocList::iterator it = find_if( m_DocList.begin(), m_DocList.end(), DocInfo::predCanonicalUnk(pCanonicalUnk) ); if ( it != m_DocList.end() ) { DocInfo * pDocInfo = *it; #ifdef DBG if ( m_ShowDialog ) DumpInfo( pDocInfo ); #endif m_DocList.erase( it ); delete pDocInfo; } else { Log( TSTR() << TEXT("Unregister of ") << WriteHex(pCanonicalUnk) << TEXT(" failed canonical unknown not found")); } pCanonicalUnk->Release(); return S_OK; } HRESULT STDMETHODCALLTYPE CAccStore::GetDocuments ( IEnumUnknown ** enumUnknown ) { EraseDeadDocuments(); EnumDocs * EnumDocuments = new EnumDocs; EnumDocuments->Init(NULL, m_DocList); HRESULT hr = EnumDocuments->QueryInterface(IID_IEnumUnknown, (void **)enumUnknown); return S_OK; } HRESULT STDMETHODCALLTYPE CAccStore::LookupByHWND ( HWND hWnd, REFIID riid, IUnknown ** ppunk ) { IMETHOD( LookupByHWND ); Log( TEXT("LookupByHWND") ); *ppunk = NULL; DocInfo * pInfo = _LookupDoc( hWnd ); if( ! pInfo ) return E_FAIL; return pInfo->m_pClonableWrapper->CloneNewWrapper( riid, (void **) ppunk ); } HRESULT STDMETHODCALLTYPE CAccStore::LookupByPoint ( POINT pt, REFIID riid, IUnknown ** ppunk ) { IMETHOD( LookupByHWND ); Log( TEXT("LookupByPoint") ); *ppunk = NULL; DocInfo * pInfo = _LookupDoc( pt ); if( ! pInfo ) return E_FAIL; return pInfo->m_pClonableWrapper->CloneNewWrapper( riid, (void **) ppunk ); } HRESULT STDMETHODCALLTYPE CAccStore::OnDocumentFocus ( IUnknown * punk ) { IMETHOD( OnDocumentFocus ); if ( m_punkFocused ) m_punkFocused->Release(); m_punkFocused = punk; if ( m_punkFocused ) m_punkFocused->AddRef(); Log( TSTR() << TEXT("OnDocumentFocus ") << WriteHex(punk) ); #ifdef DBG if ( m_ShowDialog ) { if ( punk ) { ITextStoreAnchor * pITextStoreAnchor; HRESULT hr = punk->QueryInterface( IID_ITextStoreAnchor, (void **) &pITextStoreAnchor ); Log( TSTR() << TEXT("QueryInterface for IID_ITextStoreAnchor hr=") << WriteHex(hr) << TEXT(" pITextStoreAnchor=") << pITextStoreAnchor ); #if(WINVER>=0x0500) HWND hwnd; TCHAR szWindowText[128]; pITextStoreAnchor->GetWnd( NULL, & hwnd ); Log( TSTR() << TEXT("hwnd for focused doc is ") << WriteHex(hwnd) ); GetWindowText( GetAncestor( hwnd, GA_ROOT ), szWindowText, ARRAYSIZE( szWindowText ) ); Log( TSTR() << TEXT("OnDocumentFocus succeded for ") << szWindowText ); #endif pITextStoreAnchor->Release(); } } #endif return S_OK; } HRESULT STDMETHODCALLTYPE CAccStore::GetFocused ( REFIID riid, IUnknown ** ppunk ) { IMETHOD( GetFocused ); if( ! m_punkFocused ) { *ppunk = NULL; Log( TEXT("No document has focus") ); return S_OK; } else { HRESULT hr; hr = m_punkFocused->QueryInterface( riid, (void **)ppunk ); if ( hr != S_OK ) { TraceDebugHR( hr, TSTR() << TEXT( "QueryInterface failed for ") << riid ); return hr; } return S_OK; } } void CAccStore::DumpInfo( DocInfo * pInfo ) { #ifdef DBG RECT rc = {-1,-1,-1,-1}; HRESULT hr = pInfo->m_pDoc->GetScreenExt( NULL, & rc ); TsViewCookie vcView; pInfo->m_pDoc->GetActiveView( &vcView ); HWND hwnd = NULL; if( pInfo->m_pDoc->GetWnd( vcView, & hwnd ) != S_OK ) hwnd = NULL; TCHAR str[128]; if( hr == S_OK ) { wsprintf( str, TEXT("Doc {%d,%d,%d,%d} 0x%08lX punk(0x%08lX)"), rc.left, rc.top, rc.right, rc.bottom, hwnd, pInfo->m_pCanonicalUnk ); } else { wsprintf( str, TEXT("Doc {GetScreenExt failed: 0x%08lX} 0x%08lX punk(0x%08lX)"), hr, hwnd, pInfo->m_pCanonicalUnk ); } Log( str ); #endif } void CAccStore::DumpInfo() { #ifdef DBG Log( TEXT("Dumping...") ); EraseDeadDocuments(); for( DocList::iterator i = m_DocList.begin(); i != m_DocList.end(); i++ ) { DumpInfo( *i ); } #endif } DocInfo * CAccStore::_LookupDoc( IUnknown * pCanonicalUnk ) { DocList::iterator it = find_if( m_DocList.begin(), m_DocList.end(), DocInfo::predCanonicalUnk(pCanonicalUnk) ); if ( it != m_DocList.end() ) return *it; return NULL; } DocInfo * CAccStore::_LookupDoc( HWND hWnd ) { DocList::iterator it = find_if( m_DocList.begin(), m_DocList.end(), DocInfo::predHWND(hWnd) ); if ( it != m_DocList.end() ) return *it; return NULL; } DocInfo * CAccStore::_LookupDoc( POINT pt ) { HWND hWnd = WindowFromPoint( pt ); DocList::iterator it = find_if( m_DocList.begin(), m_DocList.end(), DocInfo::predHWND(hWnd) ); if ( it != m_DocList.end() ) return *it; return NULL; } void CAccStore::EraseDeadDocuments() { // get rid of any docs that are not here any more const int cDocList = m_DocList.size(); int i = 1; for ( DocList::iterator it = m_DocList.begin(); it != m_DocList.end(); i++ ) { TS_STATUS tsStatus; DocList::iterator DocToErase = it; it++; const DocInfo& di = **DocToErase; if ( di.m_pDoc->GetStatus( &tsStatus ) != S_OK ) { m_DocList.erase( DocToErase ); Log( TEXT("Dead document erased") ); TraceDebug( TEXT("Dead document erased") ); } // make sure the list is OK if ( i > cDocList ) { Log( TEXT( "Doc list is invalid" ) ); _ASSERT( 0 ); } } return; } void CAccStore::Log( LPCTSTR text ) { #ifdef DBG if ( m_ShowDialog ) { ListBox_AddString( m_hList, text ); } #endif } /* int CAccStore::_GetText( ITextStoreAnchor * pDoc, WCHAR * pText, DWORD cchText ) { HRESULT hr = pDoc->RequestLock( DCLT_READ ); if( hr != S_OK || dcr != DC_OK ) { Log( TEXT("RequestLock failed") ); return 0; } IAnchor * paStart = NULL; hr = pDoc->GetStart( & paStart, & dcr ); if( hr != S_OK || paStart == NULL ) { pDoc->ReleaseLock(); Log( TEXT("GetStart failed") ); return 0; } DWORD cchGot = 0; hr = pDoc->GetText( paStart, NULL, pText, cchText, & cchGot, FALSE, & dcr ); paStart->Release(); pDoc->ReleaseLock(); if( hr != S_OK || dcr != S_OK ) { Log( TEXT("GetText failed") ); return 0; } return cchGot; } */