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.

463 lines
12 KiB

  1. //
  2. // snoop.cpp
  3. //
  4. // CSnoopWnd implementation.
  5. //
  6. #include "globals.h"
  7. #include "snoop.h"
  8. #include "case.h"
  9. #include "editsess.h"
  10. class CUpdateTextEditSession : public CEditSessionBase
  11. {
  12. public:
  13. CUpdateTextEditSession(ITfContext *pContext, ITfRange *pRange, CSnoopWnd *pSnoopWnd) : CEditSessionBase(pContext)
  14. {
  15. _pSnoopWnd = pSnoopWnd;
  16. _pRange = pRange;
  17. if (_pRange != NULL)
  18. {
  19. _pRange->AddRef();
  20. }
  21. }
  22. ~CUpdateTextEditSession()
  23. {
  24. SafeRelease(_pRange);
  25. }
  26. // ITfEditSession
  27. STDMETHODIMP DoEditSession(TfEditCookie ec);
  28. private:
  29. CSnoopWnd *_pSnoopWnd;
  30. ITfRange *_pRange;
  31. };
  32. #define SNOOP_X_POS 0
  33. #define SNOOP_Y_POS 0
  34. #define SNOOP_WIDTH 300
  35. #define SNOOP_HEIGHT (SNOOP_WIDTH / 3)
  36. ATOM CSnoopWnd::_atomWndClass = 0;
  37. //+---------------------------------------------------------------------------
  38. //
  39. // ctor
  40. //
  41. //----------------------------------------------------------------------------
  42. CSnoopWnd::CSnoopWnd(CCaseTextService *pCase)
  43. {
  44. _pCase = pCase; // no AddRef because CSnoopWnd is contained in the
  45. // pCase lifetime
  46. _hWnd = NULL;
  47. _cchText = 0;
  48. }
  49. //+---------------------------------------------------------------------------
  50. //
  51. // _InitClass
  52. //
  53. //----------------------------------------------------------------------------
  54. /* static */
  55. BOOL CSnoopWnd::_InitClass()
  56. {
  57. WNDCLASS wc;
  58. wc.style = 0;
  59. wc.lpfnWndProc = CSnoopWnd::_WndProc;
  60. wc.cbClsExtra = 0;
  61. wc.cbWndExtra = 0;
  62. wc.hInstance = g_hInst;
  63. wc.hIcon = NULL;
  64. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  65. wc.hbrBackground = NULL;
  66. wc.lpszMenuName = NULL;
  67. wc.lpszClassName = TEXT("SnoopWndClass");
  68. _atomWndClass = RegisterClass(&wc);
  69. return (_atomWndClass != 0);
  70. }
  71. //+---------------------------------------------------------------------------
  72. //
  73. // _UninitClass
  74. //
  75. //----------------------------------------------------------------------------
  76. /* static */
  77. void CSnoopWnd::_UninitClass()
  78. {
  79. if (_atomWndClass != 0)
  80. {
  81. UnregisterClass((LPCTSTR)_atomWndClass, g_hInst);
  82. }
  83. }
  84. //+---------------------------------------------------------------------------
  85. //
  86. // _Init
  87. //
  88. //----------------------------------------------------------------------------
  89. BOOL CSnoopWnd::_Init()
  90. {
  91. // nb: on windows 2000, you can use WS_EX_NOACTIVATE to prevent windows
  92. // from taking the foreground. We don't use that here for compatibility.
  93. // Instead, we use WS_DISABLED, which can be burdensome for more complex
  94. // ui.
  95. _hWnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
  96. (LPCTSTR)_atomWndClass,
  97. TEXT("Snoop Window"),
  98. WS_BORDER | WS_DISABLED | WS_POPUP,
  99. SNOOP_X_POS, SNOOP_Y_POS,
  100. SNOOP_WIDTH, SNOOP_HEIGHT,
  101. NULL,
  102. NULL,
  103. g_hInst,
  104. this);
  105. return (_hWnd != NULL);
  106. }
  107. //+---------------------------------------------------------------------------
  108. //
  109. // _Uninit
  110. //
  111. //----------------------------------------------------------------------------
  112. void CSnoopWnd::_Uninit()
  113. {
  114. if (_hWnd != NULL)
  115. {
  116. DestroyWindow(_hWnd);
  117. _hWnd = NULL;
  118. }
  119. }
  120. //+---------------------------------------------------------------------------
  121. //
  122. // _Show
  123. //
  124. //----------------------------------------------------------------------------
  125. void CSnoopWnd::_Show()
  126. {
  127. ShowWindow(_hWnd, SW_SHOWNA);
  128. }
  129. //+---------------------------------------------------------------------------
  130. //
  131. // _Hide
  132. //
  133. //----------------------------------------------------------------------------
  134. void CSnoopWnd::_Hide()
  135. {
  136. ShowWindow(_hWnd, SW_HIDE);
  137. }
  138. //+---------------------------------------------------------------------------
  139. //
  140. // _UpdateText
  141. //
  142. //----------------------------------------------------------------------------
  143. void CSnoopWnd::_UpdateText(ITfRange *pRange)
  144. {
  145. ITfDocumentMgr *pdmFocus;
  146. ITfContext *pContext;
  147. CUpdateTextEditSession *pEditSession;
  148. HRESULT hr;
  149. if (pRange == NULL)
  150. {
  151. // caller wants us to just use the selection in the focus doc
  152. if (_pCase->_GetThreadMgr()->GetFocus(&pdmFocus) != S_OK)
  153. return;
  154. hr = pdmFocus->GetTop(&pContext);
  155. pdmFocus->Release();
  156. if (hr != S_OK)
  157. return;
  158. }
  159. else if (pRange->GetContext(&pContext) != S_OK)
  160. return;
  161. if (pEditSession = new CUpdateTextEditSession(pContext, pRange, this))
  162. {
  163. // we need a document read lock to scan text
  164. // the CUpdateTextEditSession will do all the work when the
  165. // CUpdateTextEditSession::DoEditSession method is called by the context
  166. pContext->RequestEditSession(_pCase->_GetClientId(), pEditSession, TF_ES_READ | TF_ES_ASYNCDONTCARE, &hr);
  167. pEditSession->Release();
  168. }
  169. pContext->Release();
  170. }
  171. //+---------------------------------------------------------------------------
  172. //
  173. // DoEditSession
  174. //
  175. //----------------------------------------------------------------------------
  176. STDAPI CUpdateTextEditSession::DoEditSession(TfEditCookie ec)
  177. {
  178. _pSnoopWnd->_UpdateText(ec, _pContext, _pRange);
  179. return S_OK;
  180. }
  181. //+---------------------------------------------------------------------------
  182. //
  183. // _UpdateText
  184. //
  185. //----------------------------------------------------------------------------
  186. void CSnoopWnd::_UpdateText(TfEditCookie ec, ITfContext *pContext, ITfRange *pRange)
  187. {
  188. LONG cchBefore;
  189. LONG cchAfter;
  190. TF_SELECTION tfSelection;
  191. ULONG cFetched;
  192. BOOL fReleaseRange = FALSE;
  193. if (pRange == NULL)
  194. {
  195. // caller wants us to use the selection
  196. if (pContext->GetSelection(ec, TS_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK ||
  197. cFetched != 1)
  198. {
  199. return;
  200. }
  201. pRange = tfSelection.range; // no AddRef, take ownership of the pointer
  202. fReleaseRange = TRUE;
  203. }
  204. // arbitrarily grab some text before and after the range start anchor
  205. pRange->Collapse(ec, TF_ANCHOR_START);
  206. pRange->ShiftStart(ec, -MAX_SNOOP_TEXT / 2, &cchBefore, NULL);
  207. cchBefore = -cchBefore; // we shifted backwards, so make count a positive number
  208. pRange->GetText(ec, 0, _achText, cchBefore, (ULONG *)&cchBefore);
  209. pRange->Collapse(ec, TF_ANCHOR_END);
  210. pRange->ShiftEnd(ec, MAX_SNOOP_TEXT - cchBefore, &cchAfter, NULL);
  211. pRange->GetText(ec, 0, _achText + cchBefore, cchAfter, (ULONG *)&cchAfter);
  212. _cchText = cchBefore + cchAfter;
  213. // force a repaint
  214. InvalidateRect(_hWnd, NULL, TRUE);
  215. if (fReleaseRange)
  216. {
  217. pRange->Release();
  218. }
  219. }
  220. //+---------------------------------------------------------------------------
  221. //
  222. // _WndProc
  223. //
  224. // Snoop window proc.
  225. //----------------------------------------------------------------------------
  226. /* static */
  227. LRESULT CALLBACK CSnoopWnd::_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  228. {
  229. HDC hdc;
  230. PAINTSTRUCT ps;
  231. switch (uMsg)
  232. {
  233. case WM_CREATE:
  234. _SetThis(hWnd, lParam);
  235. return 0;
  236. case WM_PAINT:
  237. hdc = BeginPaint(hWnd, &ps);
  238. _GetThis(hWnd)->_OnPaint(hWnd, hdc);
  239. EndPaint(hWnd, &ps);
  240. return 0;
  241. }
  242. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  243. }
  244. //+---------------------------------------------------------------------------
  245. //
  246. // _OnPaint
  247. //
  248. // WM_PAINT handler for CSnoopWnd.
  249. //----------------------------------------------------------------------------
  250. void CSnoopWnd::_OnPaint(HWND hWnd, HDC hdc)
  251. {
  252. RECT rc;
  253. // background
  254. GetClientRect(hWnd, &rc);
  255. FillRect(hdc, &rc, (HBRUSH)GetStockObject(LTGRAY_BRUSH));
  256. // text
  257. TextOutW(hdc, 0, 0, _achText, _cchText);
  258. }
  259. //+---------------------------------------------------------------------------
  260. //
  261. // _InitSnoopWnd
  262. //
  263. // Create and init the snoop window.
  264. //----------------------------------------------------------------------------
  265. BOOL CCaseTextService::_InitSnoopWnd()
  266. {
  267. BOOL fThreadfocus;
  268. ITfSource *pSource = NULL;
  269. // create a snoop window
  270. if ((_pSnoopWnd = new CSnoopWnd(this)) == NULL)
  271. return FALSE;
  272. if (!_pSnoopWnd->_Init())
  273. goto ExitError;
  274. // we also need a thread focus sink
  275. if (_pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource) != S_OK)
  276. {
  277. pSource = NULL;
  278. goto ExitError;
  279. }
  280. if (pSource->AdviseSink(IID_ITfThreadFocusSink, (ITfThreadFocusSink *)this, &_dwThreadFocusSinkCookie) != S_OK)
  281. {
  282. // make sure we don't try to Unadvise _dwThreadFocusSinkCookie later
  283. _dwThreadFocusSinkCookie = TF_INVALID_COOKIE;
  284. goto ExitError;
  285. }
  286. pSource->Release();
  287. // we may need to display the snoop window right now
  288. // our thread focus sink won't be called until something changes,
  289. // so we need to check the current state.
  290. if (_pThreadMgr->IsThreadFocus(&fThreadfocus) == S_OK && fThreadfocus)
  291. {
  292. OnSetThreadFocus();
  293. }
  294. return TRUE;
  295. ExitError:
  296. SafeRelease(pSource);
  297. _UninitSnoopWnd();
  298. return FALSE;
  299. }
  300. //+---------------------------------------------------------------------------
  301. //
  302. // _UninitSnoopWnd
  303. //
  304. // Uninit and free the snoop window, unadvise the thread focus sink.
  305. //----------------------------------------------------------------------------
  306. void CCaseTextService::_UninitSnoopWnd()
  307. {
  308. ITfSource *pSource;
  309. if (_pSnoopWnd != NULL)
  310. {
  311. _pSnoopWnd->_Uninit();
  312. delete _pSnoopWnd;
  313. }
  314. if (_dwThreadFocusSinkCookie != TF_INVALID_COOKIE)
  315. {
  316. if (_pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource) == S_OK)
  317. {
  318. pSource->UnadviseSink(_dwThreadFocusSinkCookie);
  319. pSource->Release();
  320. }
  321. _dwThreadFocusSinkCookie = TF_INVALID_COOKIE;
  322. }
  323. }
  324. //+---------------------------------------------------------------------------
  325. //
  326. // _Menu_ShowSnoopWnd
  327. //
  328. // Show or hide the snoop window.
  329. //----------------------------------------------------------------------------
  330. void CCaseTextService::_Menu_ShowSnoopWnd(CCaseTextService *_this)
  331. {
  332. _this->_fShowSnoop = !_this->_fShowSnoop;
  333. if (_this->_fShowSnoop)
  334. {
  335. _this->_pSnoopWnd->_Show();
  336. }
  337. else
  338. {
  339. _this->_pSnoopWnd->_Hide();
  340. }
  341. }
  342. //+---------------------------------------------------------------------------
  343. //
  344. // OnSetThreadFocus
  345. //
  346. // Called by the system when the thread/appartment of this text service gains
  347. // the ui focus.
  348. //----------------------------------------------------------------------------
  349. STDAPI CCaseTextService::OnSetThreadFocus()
  350. {
  351. if (_fShowSnoop)
  352. {
  353. _pSnoopWnd->_Show();
  354. }
  355. return S_OK;
  356. }
  357. //+---------------------------------------------------------------------------
  358. //
  359. // OnKillThreadFocus
  360. //
  361. // Called by the system when the thread/appartment of this text service loses
  362. // the ui focus.
  363. //----------------------------------------------------------------------------
  364. STDAPI CCaseTextService::OnKillThreadFocus()
  365. {
  366. // only show our snoop window when our thread has the focus.
  367. if (_fShowSnoop)
  368. {
  369. _pSnoopWnd->_Hide();
  370. }
  371. return S_OK;
  372. }