|
|
// MSAAStore.cpp : Implementation of CAccStore
#include "stdafx.h"
#include "MSAAText.h"
#include "MSAAStore.h"
#include <windowsx.h>
#include <algorithm>
#include <stack>
using namespace std;
#include <debug.h>
#include <TSTR.h>
#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; } */
|