Leaked source code of windows server 2003
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.

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