Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

535 lines
13 KiB

  1. // MSAAStore.cpp : Implementation of CAccStore
  2. #include "stdafx.h"
  3. #include "MSAAText.h"
  4. #include "MSAAStore.h"
  5. #include <windowsx.h>
  6. #include <algorithm>
  7. #include <stack>
  8. using namespace std;
  9. #include <debug.h>
  10. #include <TSTR.h>
  11. #define ARRAYSIZE( a ) (sizeof(a)/sizeof(a[0]))
  12. CAccStore * m_pTheStore = NULL;
  13. POINT ptListOffset;
  14. POINT ptDumpOffset;
  15. BOOL fGotSize = FALSE;
  16. BOOL_PTR CALLBACK DialogProc ( HWND hwndDlg,
  17. UINT uMsg,
  18. WPARAM wParam,
  19. LPARAM lParam )
  20. {
  21. return m_pTheStore->DialogProc ( hwndDlg, uMsg, wParam, lParam );
  22. }
  23. BOOL_PTR CAccStore::DialogProc ( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  24. {
  25. switch( uMsg )
  26. {
  27. case WM_INITDIALOG:
  28. {
  29. RECT rcWnd;
  30. GetClientRect( hwndDlg, & rcWnd );
  31. RECT rcList;
  32. GetWindowRect( GetDlgItem( hwndDlg, IDC_LIST ), & rcList );
  33. MapWindowPoints( NULL, hwndDlg, (POINT *) & rcList, 2 );
  34. ptListOffset.x = rcWnd.right - ( rcList.right - rcList.left );
  35. ptListOffset.y = rcWnd.bottom - ( rcList.bottom - rcList.top );
  36. RECT rcDump;
  37. GetWindowRect( GetDlgItem( hwndDlg, ID_DUMP ), & rcDump );
  38. MapWindowPoints( NULL, hwndDlg, (POINT *) & rcDump, 2 );
  39. ptDumpOffset.x = rcWnd.right - rcDump.left;
  40. ptDumpOffset.y = rcWnd.bottom - rcDump.top;
  41. fGotSize = TRUE;
  42. break;
  43. }
  44. case WM_COMMAND:
  45. {
  46. if( LOWORD( wParam ) == ID_DUMP )
  47. {
  48. Assert( m_pTheStore );
  49. DumpInfo();
  50. break;
  51. }
  52. break;
  53. }
  54. case WM_SIZE:
  55. {
  56. if( wParam != SIZE_MINIMIZED && fGotSize )
  57. {
  58. int width = LOWORD( lParam );
  59. int height = HIWORD( lParam );
  60. SetWindowPos( GetDlgItem( hwndDlg, IDC_LIST ), NULL,
  61. 0, 0,
  62. width - ptListOffset.x, height - ptListOffset.y, SWP_NOMOVE | SWP_NOZORDER );
  63. SetWindowPos( GetDlgItem( hwndDlg, ID_DUMP ), NULL,
  64. width - ptDumpOffset.x, height - ptDumpOffset.y,
  65. 0, 0,
  66. SWP_NOSIZE | SWP_NOZORDER );
  67. }
  68. break;
  69. }
  70. }
  71. return FALSE;
  72. }
  73. /////////////////////////////////////////////////////////////////////////////
  74. // CAccStore
  75. CAccStore::CAccStore() : m_hwndDlg(NULL), m_hList(NULL), m_ShowDialog(NULL), m_punkFocused(NULL), m_pCtl(NULL), m_hInit(NULL)
  76. {
  77. IMETHOD( CAccStore );
  78. Assert( m_pTheStore == NULL );
  79. m_pTheStore = this;
  80. HRESULT hr;
  81. hr = CoCreateInstance(CLSID_MSAAControl,
  82. NULL,
  83. CLSCTX_INPROC_SERVER,
  84. IID_ITfMSAAControl,
  85. (void**)&m_pCtl);
  86. if ( hr != S_OK )
  87. {
  88. Log( TSTR() << TEXT("CoCreateInstance failed for CLSID_MSAAControl hr=") << WriteHex(hr) );
  89. }
  90. else
  91. {
  92. hr = m_pCtl->SystemEnableMSAA();
  93. if ( hr != S_OK )
  94. Log( TSTR() << TEXT("SystemEnableMSAA failed hr=") << WriteHex(hr) );
  95. }
  96. // this lets someone in another procces se if the store is up
  97. m_hInit = CreateEvent( NULL, FALSE, TRUE, TEXT("MSAA_STORE_EVENT") );
  98. CRegKey crkShowDialog;
  99. DWORD dwShowDialog = 0;
  100. if ( ( crkShowDialog.Open(HKEY_CURRENT_USER, TEXT("Control Panel\\Accessibility"), KEY_READ) == ERROR_SUCCESS ) &&
  101. ( crkShowDialog.QueryValue( dwShowDialog, TEXT("ShowDialog") ) == ERROR_SUCCESS ) &&
  102. ( dwShowDialog ) )
  103. {
  104. m_ShowDialog = true;
  105. }
  106. else
  107. {
  108. m_ShowDialog = false;
  109. }
  110. if ( m_ShowDialog )
  111. {
  112. m_hwndDlg = CreateDialog( _Module.GetModuleInstance(), MAKEINTRESOURCE( IDD_MAIN ), NULL, ::DialogProc );
  113. m_hList = GetDlgItem( m_hwndDlg, IDC_LIST );
  114. Log( TEXT("*** CAccStore ctor ***") );
  115. if ( m_pCtl == NULL )
  116. Log( TEXT("m_pCtl is null") );
  117. }
  118. }
  119. CAccStore::~CAccStore()
  120. {
  121. IMETHOD( ~CAccStore );
  122. EraseDeadDocuments();
  123. if ( m_punkFocused )
  124. m_punkFocused->Release();
  125. if ( m_pCtl )
  126. {
  127. m_pCtl->SystemDisableMSAA();
  128. m_pCtl->Release();
  129. }
  130. if ( m_hInit )
  131. CloseHandle( m_hInit );
  132. m_pTheStore = NULL;
  133. Log( TEXT("*** CAccStore dtor ***") );
  134. if ( m_ShowDialog )
  135. {
  136. EndDialog( m_hwndDlg, TRUE );
  137. }
  138. }
  139. HRESULT STDMETHODCALLTYPE CAccStore::Register (
  140. REFIID riid,
  141. IUnknown * punk
  142. )
  143. {
  144. IMETHOD( Register );
  145. EraseDeadDocuments();
  146. if( riid != IID_ITextStoreAnchor )
  147. {
  148. Log( TEXT("Register - unknown IID") );
  149. return E_NOINTERFACE;
  150. }
  151. // Get the canonical IUnknown - we use this to compare against the interface
  152. // passed to Unregister.
  153. // Note that this is from the original interface peassed in, not a wrapped
  154. // version...
  155. IUnknown * pCanonicalUnk = NULL;
  156. HRESULT hr = punk->QueryInterface( IID_IUnknown, (void **) & pCanonicalUnk );
  157. if( hr != S_OK || ! pCanonicalUnk )
  158. {
  159. Log( TEXT("QueryInterface failed") );
  160. return E_FAIL;
  161. }
  162. // Now check that the doc pointer is a clonable wrapper - if not,
  163. // wrap it using DocWrap. We need a clonable wrapper so we can hand
  164. // out individual 'head' interfaces to multiple clients.
  165. ITextStoreAnchor * pDoc = reinterpret_cast< ITextStoreAnchor * >( punk );
  166. pDoc->AddRef();
  167. IClonableWrapper * pClonableWrapper = NULL;
  168. hr = pDoc->QueryInterface( IID_IClonableWrapper, (void **) & pClonableWrapper );
  169. if( hr != S_OK || ! pClonableWrapper )
  170. {
  171. // Uh-oh - we were supposed to be given a doc that (a) supports IDocAnchor, and (b)
  172. // supports IClonableWrapper (so is usable by multiple clients).
  173. // return failure...
  174. TraceDebugHR( hr, TEXT( "QueryInterface for IID_IClonableWrapper failed") );
  175. pDoc->Release();
  176. pCanonicalUnk->Release();
  177. return E_FAIL;
  178. }
  179. // Add info to list...
  180. m_DocList.push_back( new DocInfo(pCanonicalUnk, pDoc, pClonableWrapper) );
  181. Log( TSTR() << TEXT("Register ") << WriteHex(pCanonicalUnk) << TEXT(", ") << WriteHex(pDoc) << TEXT(", ") << WriteHex(pClonableWrapper) );
  182. DumpInfo( m_DocList.back() );
  183. return S_OK;
  184. }
  185. HRESULT STDMETHODCALLTYPE CAccStore::Unregister (
  186. IUnknown * punk
  187. )
  188. {
  189. IMETHOD( Unregister );
  190. Log( TEXT("Unregister") );
  191. IUnknown * pCanonicalUnk = NULL;
  192. HRESULT hr = punk->QueryInterface( IID_IUnknown, (void **) & pCanonicalUnk );
  193. if( hr != S_OK || ! pCanonicalUnk )
  194. {
  195. return E_FAIL;
  196. }
  197. DocList::iterator it = find_if( m_DocList.begin(), m_DocList.end(), DocInfo::predCanonicalUnk(pCanonicalUnk) );
  198. if ( it != m_DocList.end() )
  199. {
  200. DocInfo * pDocInfo = *it;
  201. if ( m_ShowDialog )
  202. DumpInfo( pDocInfo );
  203. m_DocList.erase( it );
  204. delete pDocInfo;
  205. }
  206. else
  207. {
  208. Log( TSTR() << TEXT("Unregister of ") << WriteHex(pCanonicalUnk) << TEXT(" failed canonical unknown not found"));
  209. }
  210. pCanonicalUnk->Release();
  211. return S_OK;
  212. }
  213. HRESULT STDMETHODCALLTYPE CAccStore::GetDocuments (
  214. IEnumUnknown ** enumUnknown
  215. )
  216. {
  217. EraseDeadDocuments();
  218. EnumDocs * EnumDocuments = new EnumDocs;
  219. EnumDocuments->Init(NULL, m_DocList);
  220. HRESULT hr = EnumDocuments->QueryInterface(IID_IEnumUnknown, (void **)enumUnknown);
  221. return S_OK;
  222. }
  223. HRESULT STDMETHODCALLTYPE CAccStore::LookupByHWND (
  224. HWND hWnd,
  225. REFIID riid,
  226. IUnknown ** ppunk
  227. )
  228. {
  229. IMETHOD( LookupByHWND );
  230. Log( TEXT("LookupByHWND") );
  231. *ppunk = NULL;
  232. DocInfo * pInfo = _LookupDoc( hWnd );
  233. if( ! pInfo )
  234. return E_FAIL;
  235. return pInfo->m_pClonableWrapper->CloneNewWrapper( riid, (void **) ppunk );
  236. }
  237. HRESULT STDMETHODCALLTYPE CAccStore::LookupByPoint (
  238. POINT pt,
  239. REFIID riid,
  240. IUnknown ** ppunk
  241. )
  242. {
  243. IMETHOD( LookupByHWND );
  244. Log( TEXT("LookupByPoint") );
  245. *ppunk = NULL;
  246. DocInfo * pInfo = _LookupDoc( pt );
  247. if( ! pInfo )
  248. return E_FAIL;
  249. return pInfo->m_pClonableWrapper->CloneNewWrapper( riid, (void **) ppunk );
  250. }
  251. HRESULT STDMETHODCALLTYPE CAccStore::OnDocumentFocus (
  252. IUnknown * punk
  253. )
  254. {
  255. IMETHOD( OnDocumentFocus );
  256. if ( m_punkFocused )
  257. m_punkFocused->Release();
  258. m_punkFocused = punk;
  259. if ( m_punkFocused )
  260. m_punkFocused->AddRef();
  261. Log( TSTR() << TEXT("OnDocumentFocus ") << WriteHex(punk) );
  262. if ( m_ShowDialog )
  263. {
  264. if ( punk )
  265. {
  266. ITextStoreAnchor * pITextStoreAnchor;
  267. HRESULT hr = punk->QueryInterface( IID_ITextStoreAnchor, (void **) &pITextStoreAnchor );
  268. Log( TSTR() << TEXT("QueryInterface for IID_ITextStoreAnchor hr=") << WriteHex(hr) << TEXT(" pITextStoreAnchor=") << pITextStoreAnchor );
  269. #if(WINVER>=0x0500)
  270. HWND hwnd;
  271. TCHAR szWindowText[128];
  272. pITextStoreAnchor->GetWnd( NULL, & hwnd );
  273. Log( TSTR() << TEXT("hwnd for focused doc is ") << WriteHex(hwnd) );
  274. GetWindowText( GetAncestor( hwnd, GA_ROOT ), szWindowText, ARRAYSIZE( szWindowText ) );
  275. Log( TSTR() << TEXT("OnDocumentFocus succeded for ") << szWindowText );
  276. #endif
  277. pITextStoreAnchor->Release();
  278. }
  279. }
  280. return S_OK;
  281. }
  282. HRESULT STDMETHODCALLTYPE CAccStore::GetFocused (
  283. REFIID riid,
  284. IUnknown ** ppunk
  285. )
  286. {
  287. IMETHOD( GetFocused );
  288. if( ! m_punkFocused )
  289. {
  290. *ppunk = NULL;
  291. Log( TEXT("No document has focus") );
  292. return S_OK;
  293. }
  294. else
  295. {
  296. HRESULT hr;
  297. hr = m_punkFocused->QueryInterface( riid, (void **)ppunk );
  298. if ( hr != S_OK )
  299. {
  300. TraceDebugHR( hr, TSTR() << TEXT( "QueryInterface failed for ") << riid );
  301. return hr;
  302. }
  303. return S_OK;
  304. }
  305. }
  306. void CAccStore::DumpInfo( DocInfo * pInfo )
  307. {
  308. RECT rc = {-1,-1,-1,-1};
  309. HRESULT hr = pInfo->m_pDoc->GetScreenExt( NULL, & rc );
  310. TsViewCookie vcView;
  311. pInfo->m_pDoc->GetActiveView( &vcView );
  312. HWND hwnd = NULL;
  313. if( pInfo->m_pDoc->GetWnd( vcView, & hwnd ) != S_OK )
  314. hwnd = NULL;
  315. TCHAR str[80];
  316. if( hr == S_OK )
  317. {
  318. 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 );
  319. }
  320. else
  321. {
  322. wsprintf( str, TEXT("Doc {GetScreenExt failed: 0x%08lX} 0x%08lX punk(0x%08lX)"), hr, hwnd, pInfo->m_pCanonicalUnk );
  323. }
  324. Log( str );
  325. }
  326. void CAccStore::DumpInfo()
  327. {
  328. Log( TEXT("Dumping...") );
  329. EraseDeadDocuments();
  330. for( DocList::iterator i = m_DocList.begin(); i != m_DocList.end(); i++ )
  331. {
  332. DumpInfo( *i );
  333. }
  334. }
  335. DocInfo * CAccStore::_LookupDoc( IUnknown * pCanonicalUnk )
  336. {
  337. DocList::iterator it = find_if( m_DocList.begin(), m_DocList.end(), DocInfo::predCanonicalUnk(pCanonicalUnk) );
  338. if ( it != m_DocList.end() )
  339. return *it;
  340. return NULL;
  341. }
  342. DocInfo * CAccStore::_LookupDoc( HWND hWnd )
  343. {
  344. DocList::iterator it = find_if( m_DocList.begin(), m_DocList.end(), DocInfo::predHWND(hWnd) );
  345. if ( it != m_DocList.end() )
  346. return *it;
  347. return NULL;
  348. }
  349. DocInfo * CAccStore::_LookupDoc( POINT pt )
  350. {
  351. HWND hWnd = WindowFromPoint( pt );
  352. DocList::iterator it = find_if( m_DocList.begin(), m_DocList.end(), DocInfo::predHWND(hWnd) );
  353. if ( it != m_DocList.end() )
  354. return *it;
  355. return NULL;
  356. }
  357. void CAccStore::EraseDeadDocuments()
  358. {
  359. // get rid of any docs that are not here any more
  360. const int cDocList = m_DocList.size();
  361. int i = 1;
  362. for ( DocList::iterator it = m_DocList.begin(); it != m_DocList.end(); i++ )
  363. {
  364. TS_STATUS tsStatus;
  365. DocList::iterator DocToErase = it;
  366. it++;
  367. const DocInfo& di = **DocToErase;
  368. if ( di.m_pDoc->GetStatus( &tsStatus ) != S_OK )
  369. {
  370. m_DocList.erase( DocToErase );
  371. Log( TEXT("Dead document erased") );
  372. TraceDebug( TEXT("Dead document erased") );
  373. }
  374. // make sure the list is OK
  375. if ( i > cDocList )
  376. {
  377. Log( TEXT( "Doc list is invalid" ) );
  378. _ASSERT( 0 );
  379. }
  380. }
  381. return;
  382. }
  383. void CAccStore::Log( LPCTSTR text )
  384. {
  385. if ( m_ShowDialog )
  386. {
  387. ListBox_AddString( m_hList, text );
  388. }
  389. }
  390. /*
  391. int CAccStore::_GetText( ITextStoreAnchor * pDoc, WCHAR * pText, DWORD cchText )
  392. {
  393. HRESULT hr = pDoc->RequestLock( DCLT_READ );
  394. if( hr != S_OK || dcr != DC_OK )
  395. {
  396. Log( TEXT("RequestLock failed") );
  397. return 0;
  398. }
  399. IAnchor * paStart = NULL;
  400. hr = pDoc->GetStart( & paStart, & dcr );
  401. if( hr != S_OK || paStart == NULL )
  402. {
  403. pDoc->ReleaseLock();
  404. Log( TEXT("GetStart failed") );
  405. return 0;
  406. }
  407. DWORD cchGot = 0;
  408. hr = pDoc->GetText( paStart, NULL, pText, cchText, & cchGot, FALSE, & dcr );
  409. paStart->Release();
  410. pDoc->ReleaseLock();
  411. if( hr != S_OK || dcr != S_OK )
  412. {
  413. Log( TEXT("GetText failed") );
  414. return 0;
  415. }
  416. return cchGot;
  417. }
  418. */