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.

2939 lines
70 KiB

  1. /*++
  2. Copyright (c) 1999-2002 Microsoft Corporation
  3. Module Name:
  4. cmnwin.cpp
  5. Abstract:
  6. This module contains the code for the common window architecture.
  7. --*/
  8. #include "precomp.hxx"
  9. #pragma hdrstop
  10. ULONG g_WinOptions = WOPT_AUTO_ARRANGE | WOPT_AUTO_DISASM;
  11. LIST_ENTRY g_ActiveWin;
  12. PCOMMONWIN_DATA g_IndexedWin[MAXVAL_WINDOW];
  13. HWND g_IndexedHwnd[MAXVAL_WINDOW];
  14. INDEXED_FONT g_Fonts[FONT_COUNT];
  15. BOOL g_LineMarkers = FALSE;
  16. #define CW_WSP_SIG3 '3WCW'
  17. //
  18. //
  19. //
  20. COMMONWIN_DATA::COMMONWIN_DATA(ULONG ChangeBy)
  21. : StateBuffer(ChangeBy)
  22. {
  23. m_Size.cx = 0;
  24. m_Size.cy = 0;
  25. m_CausedArrange = FALSE;
  26. // Creation is an automatic operation so
  27. // InAutoOp is initialized to a non-zero value.
  28. // After CreateWindow returns it is decremented.
  29. m_InAutoOp = 1;
  30. m_enumType = MINVAL_WINDOW;
  31. m_Font = &g_Fonts[FONT_FIXED];
  32. m_FontHeight = 0;
  33. m_LineHeight = 0;
  34. m_Toolbar = NULL;
  35. m_ShowToolbar = FALSE;
  36. m_ToolbarHeight = 0;
  37. m_MinToolbarWidth = 0;
  38. m_ToolbarEdit = NULL;
  39. }
  40. void
  41. COMMONWIN_DATA::Validate()
  42. {
  43. Assert(MINVAL_WINDOW < m_enumType);
  44. Assert(m_enumType < MAXVAL_WINDOW);
  45. }
  46. void
  47. COMMONWIN_DATA::SetFont(ULONG FontIndex)
  48. {
  49. m_Font = &g_Fonts[FontIndex];
  50. m_FontHeight = m_Font->Metrics.tmHeight;
  51. m_LineHeight = m_Size.cy / m_FontHeight;
  52. }
  53. BOOL
  54. COMMONWIN_DATA::CanCopy()
  55. {
  56. if (GetFocus() == m_ToolbarEdit)
  57. {
  58. DWORD Start, End;
  59. SendMessage(m_ToolbarEdit, EM_GETSEL,
  60. (WPARAM)&Start, (WPARAM)&End);
  61. return Start != End;
  62. }
  63. else
  64. {
  65. return FALSE;
  66. }
  67. }
  68. BOOL
  69. COMMONWIN_DATA::CanCut()
  70. {
  71. if (GetFocus() == m_ToolbarEdit)
  72. {
  73. DWORD Start, End;
  74. SendMessage(m_ToolbarEdit, EM_GETSEL,
  75. (WPARAM)&Start, (WPARAM)&End);
  76. return Start != End;
  77. }
  78. else
  79. {
  80. return FALSE;
  81. }
  82. }
  83. BOOL
  84. COMMONWIN_DATA::CanPaste()
  85. {
  86. if (GetFocus() == m_ToolbarEdit)
  87. {
  88. return TRUE;
  89. }
  90. else
  91. {
  92. return FALSE;
  93. }
  94. }
  95. void
  96. COMMONWIN_DATA::Copy()
  97. {
  98. if (GetFocus() == m_ToolbarEdit)
  99. {
  100. SendMessage(m_ToolbarEdit, WM_COPY, 0, 0);
  101. }
  102. }
  103. void
  104. COMMONWIN_DATA::Cut()
  105. {
  106. if (GetFocus() == m_ToolbarEdit)
  107. {
  108. SendMessage(m_ToolbarEdit, WM_CUT, 0, 0);
  109. }
  110. }
  111. void
  112. COMMONWIN_DATA::Paste()
  113. {
  114. if (GetFocus() == m_ToolbarEdit)
  115. {
  116. SendMessage(m_ToolbarEdit, WM_PASTE, 0, 0);
  117. }
  118. }
  119. BOOL
  120. COMMONWIN_DATA::CanSelectAll()
  121. {
  122. return FALSE;
  123. }
  124. void
  125. COMMONWIN_DATA::SelectAll()
  126. {
  127. }
  128. BOOL
  129. COMMONWIN_DATA::SelectedText(PTSTR Buffer, ULONG BufferChars)
  130. {
  131. return FALSE;
  132. }
  133. BOOL
  134. COMMONWIN_DATA::CanWriteTextToFile()
  135. {
  136. return FALSE;
  137. }
  138. HRESULT
  139. COMMONWIN_DATA::WriteTextToFile(HANDLE File)
  140. {
  141. return E_NOTIMPL;
  142. }
  143. BOOL
  144. COMMONWIN_DATA::HasEditableProperties()
  145. {
  146. return FALSE;
  147. }
  148. BOOL
  149. COMMONWIN_DATA::EditProperties()
  150. /*++
  151. Returns
  152. TRUE - If properties were edited
  153. FALSE - If nothing was changed
  154. --*/
  155. {
  156. return FALSE;
  157. }
  158. HMENU
  159. COMMONWIN_DATA::GetContextMenu(void)
  160. {
  161. return NULL;
  162. }
  163. void
  164. COMMONWIN_DATA::OnContextMenuSelection(UINT Item)
  165. {
  166. // Nothing to do.
  167. }
  168. BOOL
  169. COMMONWIN_DATA::CanGotoLine(void)
  170. {
  171. return FALSE;
  172. }
  173. void
  174. COMMONWIN_DATA::GotoLine(ULONG Line)
  175. {
  176. // Do nothing.
  177. }
  178. void
  179. COMMONWIN_DATA::Find(PTSTR Text, ULONG Flags, BOOL FromDlg)
  180. {
  181. // Do nothing.
  182. }
  183. HRESULT
  184. COMMONWIN_DATA::CodeExprAtCaret(PSTR Expr, ULONG ExprSize, PULONG64 Offset)
  185. {
  186. return E_NOINTERFACE;
  187. }
  188. void
  189. COMMONWIN_DATA::ToggleBpAtCaret(void)
  190. {
  191. char CodeExpr[MAX_OFFSET_EXPR];
  192. ULONG64 Offset;
  193. if (CodeExprAtCaret(CodeExpr, DIMA(CodeExpr), &Offset) != S_OK)
  194. {
  195. MessageBeep(0);
  196. ErrorBox(NULL, 0, ERR_No_Code_For_File_Line);
  197. return;
  198. }
  199. ULONG CurBpId = DEBUG_ANY_ID;
  200. // This doesn't work too well with duplicate
  201. // breakpoints, but that should be a minor problem.
  202. if (IsBpAtOffset(NULL, Offset, &CurBpId) != BP_NONE)
  203. {
  204. PrintStringCommand(UIC_SILENT_EXECUTE, "bc %d", CurBpId);
  205. }
  206. else
  207. {
  208. PrintStringCommand(UIC_SILENT_EXECUTE, "bp %s", CodeExpr);
  209. }
  210. }
  211. BOOL
  212. COMMONWIN_DATA::OnCreate(void)
  213. {
  214. return TRUE;
  215. }
  216. LRESULT
  217. COMMONWIN_DATA::OnCommand(WPARAM wParam, LPARAM lParam)
  218. {
  219. return 1;
  220. }
  221. void
  222. COMMONWIN_DATA::OnSetFocus(void)
  223. {
  224. }
  225. void
  226. COMMONWIN_DATA::OnSize(void)
  227. {
  228. RECT Rect;
  229. // Resize the toolbar.
  230. if (m_Toolbar != NULL && m_ShowToolbar)
  231. {
  232. // If the toolbar gets too small sometimes it's better
  233. // to just let it get clipped rather than have it
  234. // try to fit into a narrow column.
  235. if (m_Size.cx >= m_MinToolbarWidth)
  236. {
  237. MoveWindow(m_Toolbar, 0, 0, m_Size.cx, m_ToolbarHeight, TRUE);
  238. }
  239. // Record what size it ended up.
  240. GetClientRect(m_Toolbar, &Rect);
  241. m_ToolbarHeight = Rect.bottom - Rect.top;
  242. if (m_FontHeight != 0)
  243. {
  244. if (m_ToolbarHeight >= m_Size.cy)
  245. {
  246. m_LineHeight = 0;
  247. }
  248. else
  249. {
  250. m_LineHeight = (m_Size.cy - m_ToolbarHeight) / m_FontHeight;
  251. }
  252. }
  253. }
  254. else
  255. {
  256. Assert(m_ToolbarHeight == 0);
  257. }
  258. }
  259. void
  260. COMMONWIN_DATA::OnButtonDown(ULONG Button)
  261. {
  262. }
  263. void
  264. COMMONWIN_DATA::OnButtonUp(ULONG Button)
  265. {
  266. }
  267. void
  268. COMMONWIN_DATA::OnMouseMove(ULONG Modifiers, ULONG X, ULONG Y)
  269. {
  270. }
  271. void
  272. COMMONWIN_DATA::OnTimer(WPARAM TimerId)
  273. {
  274. }
  275. LRESULT
  276. COMMONWIN_DATA::OnGetMinMaxInfo(LPMINMAXINFO Info)
  277. {
  278. return 1;
  279. }
  280. LRESULT
  281. COMMONWIN_DATA::OnVKeyToItem(WPARAM wParam, LPARAM lParam)
  282. {
  283. return -1;
  284. }
  285. LRESULT
  286. COMMONWIN_DATA::OnNotify(WPARAM wParam, LPARAM lParam)
  287. {
  288. return 0;
  289. }
  290. void
  291. COMMONWIN_DATA::OnUpdate(UpdateType Type)
  292. {
  293. }
  294. void
  295. COMMONWIN_DATA::OnDestroy(void)
  296. {
  297. }
  298. LRESULT
  299. COMMONWIN_DATA::OnOwnerDraw(UINT uMsg, WPARAM wParam, LPARAM lParam)
  300. {
  301. return 0;
  302. }
  303. ULONG
  304. COMMONWIN_DATA::GetWorkspaceSize(void)
  305. {
  306. return 3 * sizeof(ULONG) + sizeof(WINDOWPLACEMENT);
  307. }
  308. PUCHAR
  309. COMMONWIN_DATA::SetWorkspace(PUCHAR Data)
  310. {
  311. // First store the special signature that marks
  312. // this version of the workspace data.
  313. *(PULONG)Data = CW_WSP_SIG3;
  314. Data += sizeof(ULONG);
  315. // Store the size saved by this layer.
  316. *(PULONG)Data = COMMONWIN_DATA::GetWorkspaceSize();
  317. Data += sizeof(ULONG);
  318. //
  319. // Store the actual data.
  320. //
  321. *(PULONG)Data = m_ShowToolbar;
  322. Data += sizeof(ULONG);
  323. LPWINDOWPLACEMENT Place = (LPWINDOWPLACEMENT)Data;
  324. Place->length = sizeof(WINDOWPLACEMENT);
  325. GetWindowPlacement(m_Win, Place);
  326. Data += sizeof(WINDOWPLACEMENT);
  327. return Data;
  328. }
  329. PUCHAR
  330. COMMONWIN_DATA::ApplyWorkspace1(PUCHAR Data, PUCHAR End)
  331. {
  332. ULONG_PTR Size = End - Data;
  333. // There are three versions of the base COMMONWIN data.
  334. // 1. RECT.
  335. // 2. WINDOWPLACEMENT.
  336. // 3. CW_WSP_SIG3 sized block.
  337. // All three cases can be easily distinguished.
  338. if (Size > 2 * sizeof(ULONG) &&
  339. *(PULONG)Data == CW_WSP_SIG3 &&
  340. Size >= *(PULONG)(Data + sizeof(ULONG)))
  341. {
  342. Size = *(PULONG)(Data + sizeof(ULONG)) - 2 * sizeof(ULONG);
  343. Data += 2 * sizeof(ULONG);
  344. if (Size >= sizeof(ULONG))
  345. {
  346. SetShowToolbar(*(PULONG)Data);
  347. Size -= sizeof(ULONG);
  348. Data += sizeof(ULONG);
  349. }
  350. }
  351. if (Size >= sizeof(WINDOWPLACEMENT) &&
  352. ((LPWINDOWPLACEMENT)Data)->length == sizeof(WINDOWPLACEMENT))
  353. {
  354. LPWINDOWPLACEMENT Place = (LPWINDOWPLACEMENT)Data;
  355. if (!IsAutoArranged(m_enumType))
  356. {
  357. SetWindowPlacement(m_Win, Place);
  358. }
  359. return (PUCHAR)(Place + 1);
  360. }
  361. else
  362. {
  363. LPRECT Rect = (LPRECT)Data;
  364. Assert((PUCHAR)(Rect + 1) <= End);
  365. if (!IsAutoArranged(m_enumType))
  366. {
  367. MoveWindow(m_Win, Rect->left, Rect->top,
  368. (Rect->right - Rect->left), (Rect->bottom - Rect->top),
  369. TRUE);
  370. }
  371. return (PUCHAR)(Rect + 1);
  372. }
  373. }
  374. void
  375. COMMONWIN_DATA::UpdateColors(void)
  376. {
  377. // Nothing to do.
  378. }
  379. void
  380. COMMONWIN_DATA::UpdateSize(ULONG Width, ULONG Height)
  381. {
  382. m_Size.cx = Width;
  383. m_Size.cy = Height;
  384. if (m_FontHeight != 0)
  385. {
  386. m_LineHeight = m_Size.cy / m_FontHeight;
  387. }
  388. }
  389. void
  390. COMMONWIN_DATA::SetShowToolbar(BOOL Show)
  391. {
  392. if (!m_Toolbar)
  393. {
  394. return;
  395. }
  396. m_ShowToolbar = Show;
  397. if (m_ShowToolbar)
  398. {
  399. ShowWindow(m_Toolbar, SW_SHOW);
  400. }
  401. else
  402. {
  403. ShowWindow(m_Toolbar, SW_HIDE);
  404. m_ToolbarHeight = 0;
  405. }
  406. OnSize();
  407. if (g_Workspace != NULL)
  408. {
  409. g_Workspace->AddDirty(WSPF_DIRTY_WINDOWS);
  410. }
  411. }
  412. PCOMMONWIN_DATA
  413. NewWinData(WIN_TYPES Type)
  414. {
  415. switch(Type)
  416. {
  417. case DOC_WINDOW:
  418. return new DOCWIN_DATA;
  419. case WATCH_WINDOW:
  420. return new WATCHWIN_DATA;
  421. case LOCALS_WINDOW:
  422. return new LOCALSWIN_DATA;
  423. case CPU_WINDOW:
  424. return new CPUWIN_DATA;
  425. case DISASM_WINDOW:
  426. return new DISASMWIN_DATA;
  427. case CMD_WINDOW:
  428. return new CMDWIN_DATA;
  429. case SCRATCH_PAD_WINDOW:
  430. return new SCRATCH_PAD_DATA;
  431. case MEM_WINDOW:
  432. return new MEMWIN_DATA;
  433. #if 0
  434. case QUICKW_WINDOW:
  435. // XXX drewb - Unimplemented.
  436. return new QUICKWWIN_DATA;
  437. #endif
  438. case CALLS_WINDOW:
  439. return new CALLSWIN_DATA;
  440. case PROCESS_THREAD_WINDOW:
  441. return new PROCESS_THREAD_DATA;
  442. default:
  443. Assert(FALSE);
  444. return NULL;
  445. }
  446. }
  447. LRESULT
  448. CALLBACK
  449. COMMONWIN_DATA::WindowProc(
  450. HWND hwnd,
  451. UINT uMsg,
  452. WPARAM wParam,
  453. LPARAM lParam
  454. )
  455. {
  456. PCOMMONWIN_DATA pWinData = GetCommonWinData(hwnd);
  457. #if 0
  458. {
  459. DebugPrint("CommonWin msg %X for %p, args %X %X\n",
  460. uMsg, pWinData, wParam, lParam);
  461. }
  462. #endif
  463. if (uMsg != WM_CREATE && pWinData == NULL)
  464. {
  465. return DefMDIChildProc(hwnd, uMsg, wParam, lParam);
  466. }
  467. switch (uMsg)
  468. {
  469. case WM_CREATE:
  470. RECT rc;
  471. COMMONWIN_CREATE_DATA* Data;
  472. Assert(NULL == pWinData);
  473. Data = (COMMONWIN_CREATE_DATA*)
  474. ((LPMDICREATESTRUCT)
  475. (((CREATESTRUCT *)lParam)->lpCreateParams))->lParam;
  476. pWinData = NewWinData(Data->Type);
  477. if (!pWinData)
  478. {
  479. return -1; // Fail window creation
  480. }
  481. Assert(pWinData->m_enumType == Data->Type);
  482. pWinData->m_Win = hwnd;
  483. GetClientRect(hwnd, &rc);
  484. pWinData->m_Size.cx = rc.right;
  485. pWinData->m_Size.cy = rc.bottom;
  486. if ( !pWinData->OnCreate() )
  487. {
  488. delete pWinData;
  489. return -1; // Fail window creation
  490. }
  491. // store this in the window
  492. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pWinData);
  493. #if DBG
  494. pWinData->Validate();
  495. #endif
  496. g_IndexedWin[Data->Type] = pWinData;
  497. g_IndexedHwnd[Data->Type] = hwnd;
  498. InsertHeadList(&g_ActiveWin, &pWinData->m_ActiveWin);
  499. if (g_Workspace != NULL)
  500. {
  501. g_Workspace->AddDirty(WSPF_DIRTY_WINDOWS);
  502. }
  503. SendMessage(hwnd, WM_SETICON, 0, (LPARAM)
  504. LoadIcon(g_hInst,
  505. MAKEINTRESOURCE(pWinData->m_enumType +
  506. MINVAL_WINDOW_ICON)));
  507. // A new buffer has been created so put it in the list
  508. // then wake up the engine to fill it.
  509. Dbg_EnterCriticalSection(&g_QuickLock);
  510. InsertHeadList(&g_StateList, pWinData);
  511. Dbg_LeaveCriticalSection(&g_QuickLock);
  512. UpdateEngine();
  513. // Force initial updates so that the window starts
  514. // out with a state which matches the current debug
  515. // session's state.
  516. PostMessage(hwnd, WU_UPDATE, UPDATE_BUFFER, 0);
  517. PostMessage(hwnd, WU_UPDATE, UPDATE_EXEC, 0);
  518. if (g_WinOptions & WOPT_AUTO_ARRANGE)
  519. {
  520. Arrange();
  521. }
  522. return 0;
  523. case WM_COMMAND:
  524. if (pWinData->OnCommand(wParam, lParam) == 0)
  525. {
  526. return 0;
  527. }
  528. break;
  529. case WM_SETFOCUS:
  530. pWinData->OnSetFocus();
  531. break;
  532. case WM_MOVE:
  533. // When the frame window is minimized or restored
  534. // a move to 0,0 comes through. Ignore this so
  535. // as to not trigger the warning.
  536. if (!IsIconic(g_hwndFrame) && lParam != 0 &&
  537. !IsIconic(hwnd) && !pWinData->m_CausedArrange)
  538. {
  539. DisplayAutoArrangeWarning(pWinData);
  540. }
  541. if (g_Workspace != NULL)
  542. {
  543. g_Workspace->AddDirty(WSPF_DIRTY_WINDOWS);
  544. }
  545. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  546. case WM_SIZE:
  547. if (wParam == SIZE_MAXHIDE || wParam == SIZE_MAXSHOW)
  548. {
  549. // We don't care about cover/uncover events.
  550. break;
  551. }
  552. // We don't care about size events while the frame is
  553. // minimized as the children can't be seen. When
  554. // the frame is restored a new size event will come through
  555. // and things will get updated when they're actually visible.
  556. if (IsIconic(g_hwndFrame))
  557. {
  558. break;
  559. }
  560. if (wParam == SIZE_RESTORED && !pWinData->m_CausedArrange)
  561. {
  562. DisplayAutoArrangeWarning(pWinData);
  563. }
  564. if (g_Workspace != NULL)
  565. {
  566. g_Workspace->AddDirty(WSPF_DIRTY_WINDOWS);
  567. }
  568. pWinData->UpdateSize(LOWORD(lParam), HIWORD(lParam));
  569. // No need to run sizing code for minimize.
  570. if (wParam == SIZE_MINIMIZED)
  571. {
  572. // The minimized window will leave a hole so
  573. // arrange to fill it and leave space for the
  574. // minimized window.
  575. if (g_WinOptions & WOPT_AUTO_ARRANGE)
  576. {
  577. pWinData->m_CausedArrange = TRUE;
  578. Arrange();
  579. }
  580. break;
  581. }
  582. if (wParam == SIZE_RESTORED && pWinData->m_CausedArrange)
  583. {
  584. // If we're restoring a window that caused
  585. // a rearrange when it was minimized we
  586. // need to update things to account for it.
  587. pWinData->m_CausedArrange = FALSE;
  588. if (g_WinOptions & WOPT_AUTO_ARRANGE)
  589. {
  590. Arrange();
  591. }
  592. }
  593. else if (wParam == SIZE_MAXIMIZED)
  594. {
  595. // Ask for a rearrange on restore just
  596. // for consistency with minimize.
  597. pWinData->m_CausedArrange = TRUE;
  598. }
  599. pWinData->OnSize();
  600. break;
  601. case WM_LBUTTONDOWN:
  602. pWinData->OnButtonDown(MK_LBUTTON);
  603. return 0;
  604. case WM_LBUTTONUP:
  605. pWinData->OnButtonUp(MK_LBUTTON);
  606. return 0;
  607. case WM_MBUTTONDOWN:
  608. pWinData->OnButtonDown(MK_MBUTTON);
  609. return 0;
  610. case WM_MBUTTONUP:
  611. pWinData->OnButtonUp(MK_MBUTTON);
  612. return 0;
  613. case WM_RBUTTONDOWN:
  614. pWinData->OnButtonDown(MK_RBUTTON);
  615. return 0;
  616. case WM_RBUTTONUP:
  617. pWinData->OnButtonUp(MK_RBUTTON);
  618. return 0;
  619. case WM_MOUSEMOVE:
  620. pWinData->OnMouseMove((ULONG)wParam, LOWORD(lParam), HIWORD(lParam));
  621. return 0;
  622. case WM_TIMER:
  623. pWinData->OnTimer(wParam);
  624. return 0;
  625. case WM_GETMINMAXINFO:
  626. if (pWinData->OnGetMinMaxInfo((LPMINMAXINFO)lParam) == 0)
  627. {
  628. return 0;
  629. }
  630. break;
  631. case WM_VKEYTOITEM:
  632. return pWinData->OnVKeyToItem(wParam, lParam);
  633. case WM_NOTIFY:
  634. return pWinData->OnNotify(wParam, lParam);
  635. case WU_UPDATE:
  636. pWinData->OnUpdate((UpdateType)wParam);
  637. return 0;
  638. case WU_RECONFIGURE:
  639. pWinData->OnSize();
  640. break;
  641. case WM_DESTROY:
  642. pWinData->OnDestroy();
  643. SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL);
  644. g_IndexedWin[pWinData->m_enumType] = NULL;
  645. g_IndexedHwnd[pWinData->m_enumType] = NULL;
  646. RemoveEntryList(&pWinData->m_ActiveWin);
  647. if (g_Workspace != NULL)
  648. {
  649. g_Workspace->AddDirty(WSPF_DIRTY_WINDOWS);
  650. }
  651. // Mark this buffer as ready for cleanup by the
  652. // engine when it gets around to it.
  653. pWinData->m_Win = NULL;
  654. if (pWinData == g_FindLast)
  655. {
  656. g_FindLast = NULL;
  657. }
  658. UpdateEngine();
  659. if (g_WinOptions & WOPT_AUTO_ARRANGE)
  660. {
  661. Arrange();
  662. }
  663. break;
  664. case WM_MEASUREITEM:
  665. case WM_DRAWITEM:
  666. //
  667. // Both these messages must be handled by owner drawn windows
  668. //
  669. return pWinData->OnOwnerDraw(uMsg, wParam, lParam);
  670. case WM_CTLCOLORLISTBOX:
  671. // Substitute windbg's default window colors.
  672. SetTextColor((HDC)wParam, g_Colors[COL_PLAIN_TEXT].Color);
  673. SetBkColor((HDC)wParam, g_Colors[COL_PLAIN].Color);
  674. return (LRESULT)g_Colors[COL_PLAIN].Brush;
  675. }
  676. return DefMDIChildProc(hwnd, uMsg, wParam, lParam);
  677. }
  678. //
  679. //
  680. //
  681. SINGLE_CHILDWIN_DATA::SINGLE_CHILDWIN_DATA(ULONG ChangeBy)
  682. : COMMONWIN_DATA(ChangeBy)
  683. {
  684. m_hwndChild = NULL;
  685. }
  686. void
  687. SINGLE_CHILDWIN_DATA::Validate()
  688. {
  689. COMMONWIN_DATA::Validate();
  690. Assert(m_hwndChild);
  691. }
  692. void
  693. SINGLE_CHILDWIN_DATA::SetFont(ULONG FontIndex)
  694. {
  695. COMMONWIN_DATA::SetFont(FontIndex);
  696. SendMessage(m_hwndChild,
  697. WM_SETFONT,
  698. (WPARAM) m_Font->Font,
  699. (LPARAM) TRUE
  700. );
  701. }
  702. BOOL
  703. SINGLE_CHILDWIN_DATA::CanCopy()
  704. {
  705. if (GetFocus() != m_hwndChild)
  706. {
  707. return COMMONWIN_DATA::CanCopy();
  708. }
  709. switch (m_enumType)
  710. {
  711. default:
  712. Assert(!"Unknown type");
  713. return FALSE;
  714. case CMD_WINDOW:
  715. Assert(!"Should not be handled here since this is only for windows"
  716. " with only one child window.");
  717. return FALSE;
  718. case WATCH_WINDOW:
  719. case LOCALS_WINDOW:
  720. case CPU_WINDOW:
  721. case QUICKW_WINDOW:
  722. return -1 != ListView_GetNextItem(m_hwndChild,
  723. -1, // Find the first match
  724. LVNI_FOCUSED
  725. );
  726. case CALLS_WINDOW:
  727. return LB_ERR != SendMessage(m_hwndChild, LB_GETCURSEL, 0, 0);
  728. case DOC_WINDOW:
  729. case DISASM_WINDOW:
  730. case MEM_WINDOW:
  731. case SCRATCH_PAD_WINDOW:
  732. CHARRANGE chrg;
  733. SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&chrg);
  734. return chrg.cpMin != chrg.cpMax;
  735. case PROCESS_THREAD_WINDOW:
  736. return NULL != TreeView_GetSelection(m_hwndChild);
  737. }
  738. }
  739. BOOL
  740. SINGLE_CHILDWIN_DATA::CanCut()
  741. {
  742. if (GetFocus() != m_hwndChild)
  743. {
  744. return COMMONWIN_DATA::CanCut();
  745. }
  746. switch (m_enumType)
  747. {
  748. default:
  749. Assert(!"Unknown type");
  750. return FALSE;
  751. case CMD_WINDOW:
  752. Assert(!"Should not be handled here since this is only for windows"
  753. " with only one child window.");
  754. return FALSE;
  755. case WATCH_WINDOW:
  756. case LOCALS_WINDOW:
  757. case CPU_WINDOW:
  758. case QUICKW_WINDOW:
  759. case CALLS_WINDOW:
  760. case DOC_WINDOW:
  761. case DISASM_WINDOW:
  762. case MEM_WINDOW:
  763. case PROCESS_THREAD_WINDOW:
  764. return FALSE;
  765. case SCRATCH_PAD_WINDOW:
  766. CHARRANGE chrg;
  767. SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&chrg);
  768. return chrg.cpMin != chrg.cpMax;
  769. }
  770. }
  771. BOOL
  772. SINGLE_CHILDWIN_DATA::CanPaste()
  773. {
  774. if (GetFocus() != m_hwndChild)
  775. {
  776. return COMMONWIN_DATA::CanPaste();
  777. }
  778. switch (m_enumType)
  779. {
  780. default:
  781. Assert(!"Unknown type");
  782. return FALSE;
  783. case CMD_WINDOW:
  784. Assert(!"Should not be handled here since this is only for windows"
  785. " with only one child window.");
  786. return FALSE;
  787. case WATCH_WINDOW:
  788. case LOCALS_WINDOW:
  789. case CPU_WINDOW:
  790. case QUICKW_WINDOW:
  791. case CALLS_WINDOW:
  792. case DOC_WINDOW:
  793. case DISASM_WINDOW:
  794. case MEM_WINDOW:
  795. case PROCESS_THREAD_WINDOW:
  796. return FALSE;
  797. case SCRATCH_PAD_WINDOW:
  798. return TRUE;
  799. }
  800. }
  801. void
  802. SINGLE_CHILDWIN_DATA::Copy()
  803. {
  804. if (GetFocus() != m_hwndChild)
  805. {
  806. COMMONWIN_DATA::Copy();
  807. }
  808. else
  809. {
  810. SendMessage(m_hwndChild, WM_COPY, 0, 0);
  811. }
  812. }
  813. void
  814. SINGLE_CHILDWIN_DATA::Cut()
  815. {
  816. if (GetFocus() != m_hwndChild)
  817. {
  818. COMMONWIN_DATA::Paste();
  819. }
  820. }
  821. void
  822. SINGLE_CHILDWIN_DATA::Paste()
  823. {
  824. if (GetFocus() != m_hwndChild)
  825. {
  826. COMMONWIN_DATA::Paste();
  827. }
  828. }
  829. void
  830. SINGLE_CHILDWIN_DATA::OnSetFocus()
  831. {
  832. ::SetFocus(m_hwndChild);
  833. }
  834. void
  835. SINGLE_CHILDWIN_DATA::OnSize(void)
  836. {
  837. COMMONWIN_DATA::OnSize();
  838. MoveWindow(m_hwndChild, 0, m_ToolbarHeight,
  839. m_Size.cx, m_Size.cy - m_ToolbarHeight, TRUE);
  840. }
  841. void
  842. SINGLE_CHILDWIN_DATA::UpdateColors(void)
  843. {
  844. // Force a repaint of the child.
  845. InvalidateRect(m_hwndChild, NULL, TRUE);
  846. }
  847. //
  848. //
  849. //
  850. PROCESS_THREAD_DATA::PROCESS_THREAD_DATA()
  851. : SINGLE_CHILDWIN_DATA(512)
  852. {
  853. m_enumType = PROCESS_THREAD_WINDOW;
  854. m_TotalSystems = 0;
  855. m_NamesOffset = 0;
  856. }
  857. void
  858. PROCESS_THREAD_DATA::Validate()
  859. {
  860. SINGLE_CHILDWIN_DATA::Validate();
  861. Assert(PROCESS_THREAD_WINDOW == m_enumType);
  862. }
  863. HRESULT
  864. PROCESS_THREAD_DATA::ReadProcess(ULONG ProcId, PULONG Offset)
  865. {
  866. HRESULT Status;
  867. PULONG ThreadIds, ThreadSysIds;
  868. ULONG NumThread;
  869. char Name[MAX_PATH];
  870. ULONG NameLen;
  871. PULONG Data;
  872. if ((Status = g_pDbgSystem->
  873. SetCurrentProcessId(ProcId)) != S_OK ||
  874. (Status = g_pDbgSystem->GetNumberThreads(&NumThread)) != S_OK)
  875. {
  876. return Status;
  877. }
  878. if (FAILED(Status = g_pDbgSystem->
  879. GetCurrentProcessExecutableName(Name, sizeof(Name),
  880. NULL)))
  881. {
  882. PrintString(Name, DIMA(Name), "<%s>", FormatStatusCode(Status));
  883. }
  884. NameLen = strlen(Name) + 1;
  885. if (NameLen > 1)
  886. {
  887. PSTR NameStore = (PSTR)AddData(NameLen);
  888. if (NameStore == NULL)
  889. {
  890. return E_OUTOFMEMORY;
  891. }
  892. strcpy(NameStore, Name);
  893. }
  894. // Refresh pointers in case a resize
  895. // caused buffer movement.
  896. Data = (PULONG)GetDataBuffer() + *Offset;
  897. *Data++ = NumThread;
  898. *Data++ = NameLen;
  899. *Offset += 2;
  900. ThreadIds = Data;
  901. ThreadSysIds = ThreadIds + NumThread;
  902. if ((Status = g_pDbgSystem->
  903. GetThreadIdsByIndex(0, NumThread,
  904. ThreadIds, ThreadSysIds)) != S_OK)
  905. {
  906. return Status;
  907. }
  908. *Offset += 2 * NumThread;
  909. return S_OK;
  910. }
  911. HRESULT
  912. PROCESS_THREAD_DATA::ReadSystem(ULONG SysId,
  913. PULONG Offset)
  914. {
  915. HRESULT Status;
  916. ULONG ProcIdsOffset;
  917. PULONG ProcIds, ProcSysIds;
  918. ULONG NumProc;
  919. ULONG i;
  920. char Name[MAX_PATH + 32];
  921. ULONG NameLen;
  922. PULONG Data;
  923. if (g_pDbgSystem3)
  924. {
  925. if ((Status = g_pDbgSystem3->
  926. SetCurrentSystemId(SysId)) != S_OK ||
  927. FAILED(Status = g_pDbgSystem3->
  928. GetCurrentSystemServerName(Name, sizeof(Name), NULL)))
  929. {
  930. return Status;
  931. }
  932. }
  933. else
  934. {
  935. Name[0] = 0;
  936. }
  937. NameLen = strlen(Name) + 1;
  938. if (NameLen > 1)
  939. {
  940. PSTR NameStore = (PSTR)AddData(NameLen);
  941. if (NameStore == NULL)
  942. {
  943. return E_OUTOFMEMORY;
  944. }
  945. strcpy(NameStore, Name);
  946. }
  947. if ((Status = g_pDbgSystem->
  948. GetNumberProcesses(&NumProc)) != S_OK)
  949. {
  950. return Status;
  951. }
  952. // Refresh pointers in case a resize
  953. // caused buffer movement.
  954. Data = (PULONG)GetDataBuffer() + *Offset;
  955. *Data++ = NumProc;
  956. *Data++ = NameLen;
  957. *Offset += 2;
  958. if (NumProc == 0)
  959. {
  960. return S_OK;
  961. }
  962. ProcIds = Data;
  963. ProcIdsOffset = *Offset;
  964. ProcSysIds = ProcIds + NumProc;
  965. if ((Status = g_pDbgSystem->
  966. GetProcessIdsByIndex(0, NumProc, ProcIds, ProcSysIds)) != S_OK)
  967. {
  968. return Status;
  969. }
  970. *Offset += 2 * NumProc;
  971. for (i = 0; i < NumProc; i++)
  972. {
  973. ProcIds = (PULONG)GetDataBuffer() + ProcIdsOffset;
  974. if ((Status = ReadProcess(ProcIds[i], Offset)) != S_OK)
  975. {
  976. return Status;
  977. }
  978. }
  979. return S_OK;
  980. }
  981. HRESULT
  982. PROCESS_THREAD_DATA::ReadState(void)
  983. {
  984. HRESULT Status;
  985. ULONG CurProc;
  986. ULONG TotalSys, TotalThread, TotalProc;
  987. ULONG MaxProcThread, MaxSysThread, MaxSysProc;
  988. PULONG SysIds;
  989. ULONG i;
  990. ULONG Offset;
  991. ULONG NamesOffset;
  992. if ((Status = g_pDbgSystem->GetCurrentProcessId(&CurProc)) != S_OK)
  993. {
  994. return Status;
  995. }
  996. if (g_pDbgSystem3)
  997. {
  998. if ((Status = g_pDbgSystem3->GetNumberSystems(&TotalSys)) != S_OK ||
  999. (Status = g_pDbgSystem3->
  1000. GetTotalNumberThreadsAndProcesses(&TotalThread, &TotalProc,
  1001. &MaxProcThread, &MaxSysThread,
  1002. &MaxSysProc)) != S_OK)
  1003. {
  1004. return Status;
  1005. }
  1006. }
  1007. else
  1008. {
  1009. if ((Status = g_pDbgSystem->GetNumberProcesses(&TotalProc)) != S_OK ||
  1010. (Status = g_pDbgSystem->
  1011. GetTotalNumberThreads(&TotalThread, &MaxProcThread)) != S_OK)
  1012. {
  1013. return Status;
  1014. }
  1015. TotalSys = 1;
  1016. MaxSysThread = MaxProcThread;
  1017. MaxSysProc = TotalProc;
  1018. }
  1019. Empty();
  1020. NamesOffset = (TotalSys * 3 + TotalProc * 4 + TotalThread * 2) *
  1021. sizeof(ULONG);
  1022. SysIds = (PULONG)AddData(NamesOffset);
  1023. if (SysIds == NULL)
  1024. {
  1025. return E_OUTOFMEMORY;
  1026. }
  1027. if (g_pDbgSystem3)
  1028. {
  1029. if ((Status = g_pDbgSystem3->
  1030. GetSystemIdsByIndex(0, TotalSys, SysIds)) != S_OK)
  1031. {
  1032. return Status;
  1033. }
  1034. }
  1035. else
  1036. {
  1037. *SysIds = 0;
  1038. }
  1039. ULONG OutMask, LogMask;
  1040. // Ignore thread notifications as we're changing the thread.
  1041. g_IgnoreThreadChange = TRUE;
  1042. // Switching threads causes output which we don't want so
  1043. // ignore all output.
  1044. g_pDbgClient->GetOutputMask(&OutMask);
  1045. g_pDbgControl->GetLogMask(&LogMask);
  1046. g_pDbgClient->SetOutputMask(0);
  1047. g_pDbgControl->SetLogMask(0);
  1048. Offset = TotalSys;
  1049. for (i = 0; i < TotalSys; i++)
  1050. {
  1051. SysIds = (PULONG)GetDataBuffer();
  1052. if ((Status = ReadSystem(SysIds[i], &Offset)) != S_OK)
  1053. {
  1054. break;
  1055. }
  1056. }
  1057. // This will also set the current system and thread
  1058. // from the process information.
  1059. g_pDbgSystem->SetCurrentProcessId(CurProc);
  1060. g_IgnoreThreadChange = FALSE;
  1061. g_pDbgClient->SetOutputMask(OutMask);
  1062. g_pDbgControl->SetLogMask(LogMask);
  1063. if (Status == S_OK)
  1064. {
  1065. m_TotalSystems = TotalSys;
  1066. m_NamesOffset = NamesOffset;
  1067. }
  1068. return Status;
  1069. }
  1070. BOOL
  1071. PROCESS_THREAD_DATA::OnCreate(void)
  1072. {
  1073. if (!SINGLE_CHILDWIN_DATA::OnCreate())
  1074. {
  1075. return FALSE;
  1076. }
  1077. m_hwndChild = CreateWindow(
  1078. WC_TREEVIEW, // class name
  1079. NULL, // title
  1080. WS_CLIPSIBLINGS |
  1081. WS_CHILD | WS_VISIBLE |
  1082. WS_HSCROLL | WS_VSCROLL |
  1083. TVS_HASBUTTONS | TVS_LINESATROOT |
  1084. TVS_HASLINES, // style
  1085. 0, // x
  1086. 0, // y
  1087. m_Size.cx, // width
  1088. m_Size.cy, // height
  1089. m_Win, // parent
  1090. (HMENU) IDC_PROCESS_TREE, // control id
  1091. g_hInst, // hInstance
  1092. NULL); // user defined data
  1093. if (!m_hwndChild)
  1094. {
  1095. return FALSE;
  1096. }
  1097. SetFont(FONT_FIXED);
  1098. SendMessage(m_hwndChild, TVM_SETTEXTCOLOR,
  1099. 0, g_Colors[COL_PLAIN_TEXT].Color);
  1100. SendMessage(m_hwndChild, TVM_SETBKCOLOR,
  1101. 0, g_Colors[COL_PLAIN].Color);
  1102. return TRUE;
  1103. }
  1104. LRESULT
  1105. PROCESS_THREAD_DATA::OnNotify(WPARAM Wpm, LPARAM Lpm)
  1106. {
  1107. LPNMTREEVIEW Tvn;
  1108. HTREEITEM Sel;
  1109. Tvn = (LPNMTREEVIEW)Lpm;
  1110. if (Tvn->hdr.idFrom != IDC_PROCESS_TREE)
  1111. {
  1112. return FALSE;
  1113. }
  1114. switch(Tvn->hdr.code)
  1115. {
  1116. case TVN_SELCHANGED:
  1117. if (Tvn->action == TVC_BYMOUSE)
  1118. {
  1119. SetCurThreadFromProcessTreeItem(m_hwndChild, Tvn->itemNew.hItem);
  1120. }
  1121. break;
  1122. case NM_DBLCLK:
  1123. case NM_RETURN:
  1124. Sel = TreeView_GetSelection(m_hwndChild);
  1125. if (Sel)
  1126. {
  1127. SetCurThreadFromProcessTreeItem(m_hwndChild, Sel);
  1128. }
  1129. return TRUE;
  1130. }
  1131. return FALSE;
  1132. }
  1133. void
  1134. PROCESS_THREAD_DATA::OnUpdate(UpdateType Type)
  1135. {
  1136. if (Type != UPDATE_BUFFER &&
  1137. Type != UPDATE_EXEC)
  1138. {
  1139. return;
  1140. }
  1141. HRESULT Status;
  1142. Status = UiLockForRead();
  1143. if (Status != S_OK)
  1144. {
  1145. return;
  1146. }
  1147. ULONG Sys;
  1148. ULONG NameLen;
  1149. PULONG SysIds, Data;
  1150. char Text[MAX_PATH + 64];
  1151. PSTR Names;
  1152. TVINSERTSTRUCT Insert;
  1153. HTREEITEM CurThreadItem = NULL;
  1154. SysIds = (PULONG)GetDataBuffer();
  1155. Data = SysIds + m_TotalSystems;
  1156. Names = (PSTR)GetDataBuffer() + m_NamesOffset;
  1157. TreeView_DeleteAllItems(m_hwndChild);
  1158. for (Sys = 0; Sys < m_TotalSystems; Sys++)
  1159. {
  1160. HTREEITEM SysItem;
  1161. ULONG NumProc, Proc;
  1162. PULONG ProcIds, ProcSysIds;
  1163. NumProc = *Data++;
  1164. NameLen = *Data++;
  1165. ProcIds = Data;
  1166. ProcSysIds = ProcIds + NumProc;
  1167. Data = ProcSysIds + NumProc;
  1168. sprintf(Text, "%d ", SysIds[Sys]);
  1169. if (NameLen > 1)
  1170. {
  1171. CatString(Text, Names, DIMA(Text));
  1172. Names += strlen(Names) + 1;
  1173. }
  1174. if (m_TotalSystems > 1)
  1175. {
  1176. Insert.hParent = TVI_ROOT;
  1177. Insert.hInsertAfter = TVI_LAST;
  1178. Insert.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
  1179. Insert.item.pszText = Text;
  1180. Insert.item.state =
  1181. SysIds[Sys] == g_CurSystemId ? TVIS_EXPANDED | TVIS_BOLD: 0;
  1182. Insert.item.stateMask = TVIS_EXPANDED | TVIS_BOLD;
  1183. // Parameter is the thread ID to set to select the given system.
  1184. Insert.item.lParam = NumProc > 0 ? (LPARAM)Data[2] : (LPARAM)-1;
  1185. SysItem = TreeView_InsertItem(m_hwndChild, &Insert);
  1186. }
  1187. else
  1188. {
  1189. SysItem = TVI_ROOT;
  1190. }
  1191. for (Proc = 0; Proc < NumProc; Proc++)
  1192. {
  1193. HTREEITEM ProcItem;
  1194. ULONG NumThread, Thread;
  1195. PULONG ThreadIds, ThreadSysIds;
  1196. NumThread = *Data++;
  1197. NameLen = *Data++;
  1198. ThreadIds = Data;
  1199. ThreadSysIds = Data + NumThread;
  1200. Data = ThreadSysIds + NumThread;
  1201. sprintf(Text, "%03d:%x ", ProcIds[Proc], ProcSysIds[Proc]);
  1202. if (NameLen > 1)
  1203. {
  1204. CatString(Text, Names, DIMA(Text));
  1205. Names += strlen(Names) + 1;
  1206. }
  1207. Insert.hParent = SysItem;
  1208. Insert.hInsertAfter = TVI_LAST;
  1209. Insert.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
  1210. Insert.item.pszText = Text;
  1211. Insert.item.state =
  1212. SysIds[Sys] == g_CurSystemId &&
  1213. ProcIds[Proc] == g_CurProcessId ?
  1214. TVIS_EXPANDED | TVIS_BOLD: 0;
  1215. Insert.item.stateMask = TVIS_EXPANDED | TVIS_BOLD;
  1216. // Parameter is the thread ID to set to select the given thread.
  1217. Insert.item.lParam = (LPARAM)ThreadIds[0];
  1218. ProcItem = TreeView_InsertItem(m_hwndChild, &Insert);
  1219. for (Thread = 0; Thread < NumThread; Thread++)
  1220. {
  1221. HTREEITEM ThreadItem;
  1222. sprintf(Text, "%03d:%x",
  1223. ThreadIds[Thread], ThreadSysIds[Thread]);
  1224. Insert.hParent = ProcItem;
  1225. Insert.hInsertAfter = TVI_LAST;
  1226. Insert.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
  1227. Insert.item.pszText = Text;
  1228. Insert.item.state =
  1229. SysIds[Sys] == g_CurSystemId &&
  1230. ProcIds[Proc] == g_CurProcessId &&
  1231. ThreadIds[Thread] == g_CurThreadId ?
  1232. TVIS_BOLD : 0;
  1233. Insert.item.stateMask = TVIS_BOLD;
  1234. Insert.item.lParam = (LPARAM)ThreadIds[Thread];
  1235. ThreadItem = TreeView_InsertItem(m_hwndChild, &Insert);
  1236. if (Insert.item.state & TVIS_BOLD)
  1237. {
  1238. CurThreadItem = ThreadItem;
  1239. }
  1240. }
  1241. }
  1242. }
  1243. if (CurThreadItem)
  1244. {
  1245. TreeView_Select(m_hwndChild, CurThreadItem, TVGN_CARET);
  1246. }
  1247. UnlockStateBuffer(this);
  1248. }
  1249. void
  1250. PROCESS_THREAD_DATA::UpdateColors(void)
  1251. {
  1252. SendMessage(m_hwndChild, TVM_SETTEXTCOLOR,
  1253. 0, g_Colors[COL_PLAIN_TEXT].Color);
  1254. SendMessage(m_hwndChild, TVM_SETBKCOLOR,
  1255. 0, g_Colors[COL_PLAIN].Color);
  1256. InvalidateRect(m_hwndChild, NULL, TRUE);
  1257. }
  1258. void
  1259. PROCESS_THREAD_DATA::SetCurThreadFromProcessTreeItem(HWND Tree, HTREEITEM Sel)
  1260. {
  1261. TVITEM Item;
  1262. Item.hItem = Sel;
  1263. Item.mask = TVIF_CHILDREN | TVIF_PARAM;
  1264. TreeView_GetItem(Tree, &Item);
  1265. if (Item.lParam != (LPARAM)-1)
  1266. {
  1267. g_pUiSystem->SetCurrentThreadId((ULONG)Item.lParam);
  1268. }
  1269. }
  1270. //
  1271. //
  1272. //
  1273. EDITWIN_DATA::EDITWIN_DATA(ULONG ChangeBy)
  1274. : SINGLE_CHILDWIN_DATA(ChangeBy)
  1275. {
  1276. m_TextLines = 0;
  1277. m_Highlights = NULL;
  1278. }
  1279. void
  1280. EDITWIN_DATA::Validate()
  1281. {
  1282. SINGLE_CHILDWIN_DATA::Validate();
  1283. }
  1284. void
  1285. EDITWIN_DATA::SetFont(ULONG FontIndex)
  1286. {
  1287. SINGLE_CHILDWIN_DATA::SetFont(FontIndex);
  1288. // Force the tabstop size to be recomputed
  1289. // with the new font.
  1290. SendMessage(m_hwndChild, EM_SETTABSTOPS, 1, (LPARAM)&g_TabWidth);
  1291. }
  1292. BOOL
  1293. EDITWIN_DATA::CanSelectAll()
  1294. {
  1295. return TRUE;
  1296. }
  1297. void
  1298. EDITWIN_DATA::SelectAll()
  1299. {
  1300. CHARRANGE Sel;
  1301. Sel.cpMin = 0;
  1302. Sel.cpMax = INT_MAX;
  1303. SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&Sel);
  1304. }
  1305. BOOL
  1306. EDITWIN_DATA::OnCreate(void)
  1307. {
  1308. m_hwndChild = CreateWindowEx(
  1309. WS_EX_CLIENTEDGE, // Extended style
  1310. RICHEDIT_CLASS, // class name
  1311. NULL, // title
  1312. WS_CLIPSIBLINGS
  1313. | WS_CHILD | WS_VISIBLE
  1314. | WS_VSCROLL | ES_AUTOVSCROLL
  1315. | WS_HSCROLL | ES_AUTOHSCROLL
  1316. | ES_READONLY
  1317. | ES_MULTILINE, // style
  1318. 0, // x
  1319. m_ToolbarHeight, // y
  1320. m_Size.cx, // width
  1321. m_Size.cy - m_ToolbarHeight, // height
  1322. m_Win, // parent
  1323. (HMENU) 0, // control id
  1324. g_hInst, // hInstance
  1325. NULL); // user defined data
  1326. if (m_hwndChild)
  1327. {
  1328. CHARFORMAT2 Fmt;
  1329. SetFont(FONT_FIXED);
  1330. SendMessage(m_hwndChild, EM_SETBKGNDCOLOR, FALSE,
  1331. g_Colors[COL_PLAIN].Color);
  1332. ZeroMemory(&Fmt, sizeof(Fmt));
  1333. Fmt.cbSize = sizeof(Fmt);
  1334. Fmt.dwMask = CFM_COLOR;
  1335. Fmt.crTextColor = g_Colors[COL_PLAIN_TEXT].Color;
  1336. SendMessage(m_hwndChild, EM_SETCHARFORMAT,
  1337. SCF_SELECTION, (LPARAM)&Fmt);
  1338. }
  1339. return m_hwndChild != NULL;
  1340. }
  1341. LRESULT
  1342. EDITWIN_DATA::OnNotify(WPARAM Wpm, LPARAM Lpm)
  1343. {
  1344. NMHDR* Hdr = (NMHDR*)Lpm;
  1345. if (Hdr->code == EN_SAVECLIPBOARD)
  1346. {
  1347. // Indicate that the clipboard contents should
  1348. // be kept alive.
  1349. return 0;
  1350. }
  1351. else if (Hdr->code == EN_MSGFILTER)
  1352. {
  1353. MSGFILTER* Filter = (MSGFILTER*)Lpm;
  1354. if (WM_SYSKEYDOWN == Filter->msg ||
  1355. WM_SYSKEYUP == Filter->msg ||
  1356. WM_SYSCHAR == Filter->msg)
  1357. {
  1358. // Force default processing for menu operations
  1359. // so that the Alt-minus menu comes up.
  1360. return 1;
  1361. }
  1362. }
  1363. return 0;
  1364. }
  1365. void
  1366. EDITWIN_DATA::OnDestroy(void)
  1367. {
  1368. EDIT_HIGHLIGHT* Next;
  1369. while (m_Highlights != NULL)
  1370. {
  1371. Next = m_Highlights->Next;
  1372. delete m_Highlights;
  1373. m_Highlights = Next;
  1374. }
  1375. SINGLE_CHILDWIN_DATA::OnDestroy();
  1376. }
  1377. void
  1378. EDITWIN_DATA::UpdateColors(void)
  1379. {
  1380. RicheditUpdateColors(m_hwndChild,
  1381. g_Colors[COL_PLAIN_TEXT].Color, TRUE,
  1382. g_Colors[COL_PLAIN].Color, TRUE);
  1383. UpdateCurrentLineHighlight();
  1384. UpdateBpMarks();
  1385. }
  1386. void
  1387. EDITWIN_DATA::SetCurrentLineHighlight(ULONG Line)
  1388. {
  1389. //
  1390. // Clear any other current line highlight in this window.
  1391. // Also, only one doc window can have a current IP highlight so if
  1392. // this is a doc window getting a current IP highlight make
  1393. // sure no other doc windows have a current IP highlight.
  1394. //
  1395. if (m_enumType == DOC_WINDOW && ULONG_MAX != Line)
  1396. {
  1397. RemoveActiveWinHighlights(1 << DOC_WINDOW, EHL_CURRENT_LINE);
  1398. }
  1399. else
  1400. {
  1401. RemoveAllHighlights(EHL_CURRENT_LINE);
  1402. }
  1403. if (ULONG_MAX != Line)
  1404. {
  1405. AddHighlight(Line, EHL_CURRENT_LINE);
  1406. RicheditScrollToLine(m_hwndChild, Line, m_LineHeight);
  1407. }
  1408. }
  1409. void
  1410. EDITWIN_DATA::UpdateCurrentLineHighlight(void)
  1411. {
  1412. EDIT_HIGHLIGHT* Hl;
  1413. for (Hl = m_Highlights; Hl != NULL; Hl = Hl->Next)
  1414. {
  1415. if (Hl->Flags & EHL_CURRENT_LINE)
  1416. {
  1417. break;
  1418. }
  1419. }
  1420. if (Hl)
  1421. {
  1422. ApplyHighlight(Hl);
  1423. }
  1424. }
  1425. EDIT_HIGHLIGHT*
  1426. EDITWIN_DATA::GetLineHighlighting(ULONG Line)
  1427. {
  1428. EDIT_HIGHLIGHT* Hl;
  1429. for (Hl = m_Highlights; Hl != NULL; Hl = Hl->Next)
  1430. {
  1431. if (Hl->Line == Line)
  1432. {
  1433. return Hl;
  1434. }
  1435. }
  1436. return NULL;
  1437. }
  1438. void
  1439. EDITWIN_DATA::ApplyHighlight(EDIT_HIGHLIGHT* Hl)
  1440. {
  1441. CHARRANGE OldSel;
  1442. BOOL HasFocus = ::GetFocus() == m_hwndChild;
  1443. // Get the old selection and scroll position.
  1444. SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&OldSel);
  1445. // Disable the window to prevent auto-scrolling
  1446. // when the selection is set.
  1447. EnableWindow(m_hwndChild, FALSE);
  1448. //
  1449. // Compute the highlight information.
  1450. //
  1451. char Markers[LINE_MARKERS + 1];
  1452. CHARFORMAT2 Fmt;
  1453. ULONG TextCol, BgCol;
  1454. Markers[2] = 0;
  1455. ZeroMemory(&Fmt, sizeof(Fmt));
  1456. Fmt.cbSize = sizeof(Fmt);
  1457. Fmt.dwMask = CFM_COLOR | CFM_BACKCOLOR;
  1458. if (Hl->Flags & EHL_CURRENT_LINE)
  1459. {
  1460. Markers[1] = '>';
  1461. switch(Hl->Flags & EHL_ANY_BP)
  1462. {
  1463. case EHL_ENABLED_BP:
  1464. Markers[0] = 'B';
  1465. TextCol = COL_BP_CURRENT_LINE_TEXT;
  1466. BgCol = COL_BP_CURRENT_LINE;
  1467. break;
  1468. case EHL_DISABLED_BP:
  1469. Markers[0] = 'D';
  1470. TextCol = COL_BP_CURRENT_LINE_TEXT;
  1471. BgCol = COL_BP_CURRENT_LINE;
  1472. break;
  1473. default:
  1474. Markers[0] = ' ';
  1475. TextCol = COL_CURRENT_LINE_TEXT;
  1476. BgCol = COL_CURRENT_LINE;
  1477. break;
  1478. }
  1479. }
  1480. else
  1481. {
  1482. Markers[1] = ' ';
  1483. switch(Hl->Flags & EHL_ANY_BP)
  1484. {
  1485. case EHL_ENABLED_BP:
  1486. Markers[0] = 'B';
  1487. TextCol = COL_ENABLED_BP_TEXT;
  1488. BgCol = COL_ENABLED_BP;
  1489. break;
  1490. case EHL_DISABLED_BP:
  1491. Markers[0] = 'D';
  1492. TextCol = COL_DISABLED_BP_TEXT;
  1493. BgCol = COL_DISABLED_BP;
  1494. break;
  1495. default:
  1496. Markers[0] = ' ';
  1497. TextCol = COL_PLAIN_TEXT;
  1498. BgCol = COL_PLAIN;
  1499. break;
  1500. }
  1501. }
  1502. Fmt.crTextColor = g_Colors[TextCol].Color;
  1503. Fmt.crBackColor = g_Colors[BgCol].Color;
  1504. //
  1505. // Select the line to be highlighted
  1506. //
  1507. CHARRANGE FmtSel;
  1508. FmtSel.cpMin = (LONG)SendMessage(m_hwndChild, EM_LINEINDEX, Hl->Line, 0);
  1509. if (g_LineMarkers)
  1510. {
  1511. // Replace the markers at the beginning of the line.
  1512. FmtSel.cpMax = FmtSel.cpMin + 2;
  1513. SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&FmtSel);
  1514. SendMessage(m_hwndChild, EM_REPLACESEL, FALSE, (LPARAM)Markers);
  1515. }
  1516. // Color the line.
  1517. FmtSel.cpMax = FmtSel.cpMin + (LONG)
  1518. SendMessage(m_hwndChild, EM_LINELENGTH, FmtSel.cpMin, 0) + 1;
  1519. if (g_LineMarkers)
  1520. {
  1521. FmtSel.cpMin += 2;
  1522. }
  1523. SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&FmtSel);
  1524. SendMessage(m_hwndChild, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&Fmt);
  1525. // Restore the old selection
  1526. SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&OldSel);
  1527. EnableWindow(m_hwndChild, TRUE);
  1528. // The disabling of the window caused the richedit
  1529. // to forget its focus status so force the focus
  1530. // back if it had it.
  1531. if (HasFocus)
  1532. {
  1533. ::SetFocus(m_hwndChild);
  1534. }
  1535. }
  1536. EDIT_HIGHLIGHT*
  1537. EDITWIN_DATA::AddHighlight(ULONG Line, ULONG Flags)
  1538. {
  1539. EDIT_HIGHLIGHT* Hl;
  1540. // Search for an existing highlight record for the line.
  1541. Hl = GetLineHighlighting(Line);
  1542. if (Hl == NULL)
  1543. {
  1544. Hl = new EDIT_HIGHLIGHT;
  1545. if (Hl == NULL)
  1546. {
  1547. return NULL;
  1548. }
  1549. Hl->Data = 0;
  1550. Hl->Line = Line;
  1551. Hl->Flags = 0;
  1552. Hl->Next = m_Highlights;
  1553. m_Highlights = Hl;
  1554. }
  1555. Hl->Flags |= Flags;
  1556. ApplyHighlight(Hl);
  1557. return Hl;
  1558. }
  1559. void
  1560. EDITWIN_DATA::RemoveHighlight(ULONG Line, ULONG Flags)
  1561. {
  1562. EDIT_HIGHLIGHT* Hl;
  1563. EDIT_HIGHLIGHT* Prev;
  1564. // Search for an existing highlight record for the line.
  1565. Prev = NULL;
  1566. for (Hl = m_Highlights; Hl != NULL; Hl = Hl->Next)
  1567. {
  1568. if (Hl->Line == Line)
  1569. {
  1570. break;
  1571. }
  1572. Prev = Hl;
  1573. }
  1574. if (Hl == NULL)
  1575. {
  1576. return;
  1577. }
  1578. Hl->Flags &= ~Flags;
  1579. ApplyHighlight(Hl);
  1580. if (Hl->Flags == 0)
  1581. {
  1582. if (Prev == NULL)
  1583. {
  1584. m_Highlights = Hl->Next;
  1585. }
  1586. else
  1587. {
  1588. Prev->Next = Hl->Next;
  1589. }
  1590. delete Hl;
  1591. }
  1592. }
  1593. void
  1594. EDITWIN_DATA::RemoveAllHighlights(ULONG Flags)
  1595. {
  1596. EDIT_HIGHLIGHT* Hl;
  1597. EDIT_HIGHLIGHT* Next;
  1598. EDIT_HIGHLIGHT* Prev;
  1599. Prev = NULL;
  1600. for (Hl = m_Highlights; Hl != NULL; Hl = Next)
  1601. {
  1602. Next = Hl->Next;
  1603. if (Hl->Flags & Flags)
  1604. {
  1605. Hl->Flags &= ~Flags;
  1606. ApplyHighlight(Hl);
  1607. if (Hl->Flags == 0)
  1608. {
  1609. if (Prev == NULL)
  1610. {
  1611. m_Highlights = Hl->Next;
  1612. }
  1613. else
  1614. {
  1615. Prev->Next = Hl->Next;
  1616. }
  1617. delete Hl;
  1618. }
  1619. else
  1620. {
  1621. Prev = Hl;
  1622. }
  1623. }
  1624. else
  1625. {
  1626. Prev = Hl;
  1627. }
  1628. }
  1629. }
  1630. void
  1631. EDITWIN_DATA::RemoveActiveWinHighlights(ULONG Types, ULONG Flags)
  1632. {
  1633. PLIST_ENTRY Entry = g_ActiveWin.Flink;
  1634. while (Entry != &g_ActiveWin)
  1635. {
  1636. PEDITWIN_DATA WinData = (PEDITWIN_DATA)
  1637. ACTIVE_WIN_ENTRY(Entry);
  1638. if (Types & (1 << WinData->m_enumType))
  1639. {
  1640. WinData->RemoveAllHighlights(Flags);
  1641. }
  1642. Entry = Entry->Flink;
  1643. }
  1644. }
  1645. void
  1646. EDITWIN_DATA::UpdateBpMarks(void)
  1647. {
  1648. // Empty implementation for derived classes
  1649. // that do not show BP marks.
  1650. }
  1651. int
  1652. EDITWIN_DATA::CheckForFileChanges(PCSTR File, FILETIME* LastWrite)
  1653. {
  1654. HANDLE Handle;
  1655. Handle = CreateFile(File, GENERIC_READ, FILE_SHARE_READ,
  1656. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  1657. NULL);
  1658. if (Handle == INVALID_HANDLE_VALUE)
  1659. {
  1660. goto Changed;
  1661. }
  1662. FILETIME NewWrite;
  1663. if (!GetFileTime(Handle, NULL, NULL, &NewWrite))
  1664. {
  1665. if (!GetFileTime(Handle, &NewWrite, NULL, NULL))
  1666. {
  1667. ZeroMemory(&NewWrite, sizeof(NewWrite));
  1668. }
  1669. }
  1670. CloseHandle(Handle);
  1671. if (CompareFileTime(LastWrite, &NewWrite) == 0)
  1672. {
  1673. // No change.
  1674. return IDCANCEL;
  1675. }
  1676. Changed:
  1677. return
  1678. g_QuietSourceMode == QMODE_ALWAYS_YES ? IDYES :
  1679. (g_QuietSourceMode == QMODE_ALWAYS_NO ? IDCANCEL :
  1680. QuestionBox(ERR_File_Has_Changed, MB_YESNO, File));
  1681. }
  1682. //
  1683. //
  1684. //
  1685. SCRATCH_PAD_DATA::SCRATCH_PAD_DATA()
  1686. : EDITWIN_DATA(16)
  1687. {
  1688. m_enumType = SCRATCH_PAD_WINDOW;
  1689. }
  1690. void
  1691. SCRATCH_PAD_DATA::Validate()
  1692. {
  1693. EDITWIN_DATA::Validate();
  1694. Assert(SCRATCH_PAD_WINDOW == m_enumType);
  1695. }
  1696. void
  1697. SCRATCH_PAD_DATA::Cut()
  1698. {
  1699. SendMessage(m_hwndChild, WM_CUT, 0, 0);
  1700. }
  1701. void
  1702. SCRATCH_PAD_DATA::Paste()
  1703. {
  1704. SendMessage(m_hwndChild, EM_PASTESPECIAL, CF_TEXT, 0);
  1705. }
  1706. BOOL
  1707. SCRATCH_PAD_DATA::CanWriteTextToFile()
  1708. {
  1709. return TRUE;
  1710. }
  1711. HRESULT
  1712. SCRATCH_PAD_DATA::WriteTextToFile(HANDLE File)
  1713. {
  1714. return RicheditWriteToFile(m_hwndChild, File);
  1715. }
  1716. BOOL
  1717. SCRATCH_PAD_DATA::OnCreate(void)
  1718. {
  1719. if (!EDITWIN_DATA::OnCreate())
  1720. {
  1721. return FALSE;
  1722. }
  1723. SendMessage(m_hwndChild, EM_SETOPTIONS, ECOOP_AND, ~ECO_READONLY);
  1724. SendMessage(m_hwndChild, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS);
  1725. return TRUE;
  1726. }
  1727. LRESULT
  1728. SCRATCH_PAD_DATA::OnNotify(WPARAM Wpm, LPARAM Lpm)
  1729. {
  1730. MSGFILTER* Filter = (MSGFILTER *)Lpm;
  1731. if (EN_MSGFILTER != Filter->nmhdr.code)
  1732. {
  1733. return 0;
  1734. }
  1735. if (WM_RBUTTONDOWN == Filter->msg ||
  1736. WM_RBUTTONDBLCLK == Filter->msg)
  1737. {
  1738. // If there's a selection copy it to the clipboard
  1739. // and clear it. Otherwise try to paste.
  1740. if (CanCopy())
  1741. {
  1742. Copy();
  1743. CHARRANGE Sel;
  1744. SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&Sel);
  1745. Sel.cpMax = Sel.cpMin;
  1746. SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&Sel);
  1747. }
  1748. else if (SendMessage(m_hwndChild, EM_CANPASTE, CF_TEXT, 0))
  1749. {
  1750. Paste();
  1751. }
  1752. // Ignore right-button events.
  1753. return 1;
  1754. }
  1755. return 0;
  1756. }
  1757. //
  1758. //
  1759. //
  1760. DISASMWIN_DATA::DISASMWIN_DATA()
  1761. : EDITWIN_DATA(2048)
  1762. {
  1763. m_enumType = DISASM_WINDOW;
  1764. sprintf(m_OffsetExpr, "0x%I64x", g_EventIp);
  1765. m_UpdateExpr = FALSE;
  1766. m_FirstInstr = 0;
  1767. m_LastInstr = 0;
  1768. }
  1769. void
  1770. DISASMWIN_DATA::Validate()
  1771. {
  1772. EDITWIN_DATA::Validate();
  1773. Assert(DISASM_WINDOW == m_enumType);
  1774. }
  1775. HRESULT
  1776. DISASMWIN_DATA::ReadState(void)
  1777. {
  1778. HRESULT Status;
  1779. // Sample these values right away in case the UI changes them.
  1780. ULONG LinesTotal = m_LineHeight;
  1781. ULONG LinesBefore = LinesTotal / 2;
  1782. DEBUG_VALUE Value;
  1783. if ((Status = g_pDbgControl->Evaluate(m_OffsetExpr, DEBUG_VALUE_INT64,
  1784. &Value, NULL)) != S_OK)
  1785. {
  1786. return Status;
  1787. }
  1788. m_PrimaryInstr = Value.I64;
  1789. // Reserve space at the beginning of the buffer to
  1790. // store the line to offset mapping table.
  1791. PULONG64 LineMap;
  1792. Empty();
  1793. LineMap = (PULONG64)AddData(sizeof(ULONG64) * LinesTotal);
  1794. if (LineMap == NULL)
  1795. {
  1796. return E_OUTOFMEMORY;
  1797. }
  1798. // We also need to allocate a temporary line map to
  1799. // pass to the engine for filling. This can't be
  1800. // the state buffer data since that may move as
  1801. // output is generated.
  1802. LineMap = new ULONG64[LinesTotal];
  1803. if (LineMap == NULL)
  1804. {
  1805. return E_OUTOFMEMORY;
  1806. }
  1807. g_OutStateBuf.SetBuffer(this);
  1808. if ((Status = g_OutStateBuf.Start(FALSE)) != S_OK)
  1809. {
  1810. delete [] LineMap;
  1811. return Status;
  1812. }
  1813. Status = g_pOutCapControl->
  1814. OutputDisassemblyLines(DEBUG_OUTCTL_THIS_CLIENT |
  1815. DEBUG_OUTCTL_OVERRIDE_MASK |
  1816. DEBUG_OUTCTL_NOT_LOGGED,
  1817. LinesBefore, LinesTotal, m_PrimaryInstr,
  1818. DEBUG_DISASM_EFFECTIVE_ADDRESS |
  1819. DEBUG_DISASM_MATCHING_SYMBOLS,
  1820. &m_PrimaryLine, &m_FirstInstr, &m_LastInstr,
  1821. LineMap);
  1822. memcpy(m_Data, LineMap, sizeof(ULONG64) * LinesTotal);
  1823. delete [] LineMap;
  1824. if (Status != S_OK)
  1825. {
  1826. g_OutStateBuf.End(FALSE);
  1827. return Status;
  1828. }
  1829. m_TextLines = LinesTotal;
  1830. m_TextOffset = LinesTotal * sizeof(ULONG64);
  1831. // The line map is generated with offsets followed by
  1832. // invalid offsets for continuation lines. We want
  1833. // the offsets to be on the last line of the disassembly
  1834. // for a continuation set so move them down.
  1835. // We don't want to move the offsets down to blank lines,
  1836. // though, such as the blank lines that separate bundles
  1837. // in IA64 disassembly.
  1838. LineMap = (PULONG64)m_Data;
  1839. PULONG64 LineMapEnd = LineMap + m_TextLines;
  1840. PULONG64 SetStart;
  1841. PSTR Text = (PSTR)m_Data + m_TextOffset;
  1842. PSTR PrevText;
  1843. while (LineMap < LineMapEnd)
  1844. {
  1845. if (*LineMap != DEBUG_INVALID_OFFSET)
  1846. {
  1847. SetStart = LineMap;
  1848. for (;;)
  1849. {
  1850. PrevText = Text;
  1851. Text = strchr(Text, '\n') + 1;
  1852. LineMap++;
  1853. if (LineMap >= LineMapEnd ||
  1854. *LineMap != DEBUG_INVALID_OFFSET ||
  1855. *Text == '\n')
  1856. {
  1857. break;
  1858. }
  1859. }
  1860. LineMap--;
  1861. Text = PrevText;
  1862. if (LineMap > SetStart)
  1863. {
  1864. *LineMap = *SetStart;
  1865. *SetStart = DEBUG_INVALID_OFFSET;
  1866. }
  1867. }
  1868. LineMap++;
  1869. Text = strchr(Text, '\n') + 1;
  1870. }
  1871. #ifdef DEBUG_DISASM
  1872. LineMap = (PULONG64)m_Data;
  1873. for (Line = 0; Line < m_TextLines; Line++)
  1874. {
  1875. DebugPrint("%d: %I64x\n", Line, LineMap[Line]);
  1876. }
  1877. #endif
  1878. return g_OutStateBuf.End(TRUE);
  1879. }
  1880. HRESULT
  1881. DISASMWIN_DATA::CodeExprAtCaret(PSTR Expr, ULONG ExprSize, PULONG64 Offset)
  1882. {
  1883. HRESULT Status;
  1884. LRESULT LineChar;
  1885. LONG Line;
  1886. PULONG64 LineMap;
  1887. if ((Status = UiLockForRead()) != S_OK)
  1888. {
  1889. // Don't want to return any success codes here.
  1890. return FAILED(Status) ? Status : E_FAIL;
  1891. }
  1892. LineChar = SendMessage(m_hwndChild, EM_LINEINDEX, -1, 0);
  1893. Line = (LONG)SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0, LineChar);
  1894. if (Line < 0 || (ULONG)Line >= m_TextLines)
  1895. {
  1896. Status = E_INVALIDARG;
  1897. goto Unlock;
  1898. }
  1899. ULONG64 LineOff;
  1900. // Look up the offset in the line map. If it's part of
  1901. // a multiline group move forward to the offset.
  1902. LineMap = (PULONG64)m_Data;
  1903. LineOff = LineMap[Line];
  1904. while ((ULONG)(Line + 1) < m_TextLines && LineOff == DEBUG_INVALID_OFFSET)
  1905. {
  1906. Line++;
  1907. LineOff = LineMap[Line];
  1908. }
  1909. if (Expr != NULL)
  1910. {
  1911. if (!PrintString(Expr, ExprSize, "0x%I64x", LineOff))
  1912. {
  1913. Status = E_INVALIDARG;
  1914. goto Unlock;
  1915. }
  1916. }
  1917. if (Offset != NULL)
  1918. {
  1919. *Offset = LineOff;
  1920. }
  1921. Status = S_OK;
  1922. Unlock:
  1923. UnlockStateBuffer(this);
  1924. return Status;
  1925. }
  1926. BOOL
  1927. DISASMWIN_DATA::OnCreate(void)
  1928. {
  1929. RECT Rect;
  1930. ULONG Height;
  1931. Height = GetSystemMetrics(SM_CYVSCROLL) + 4 * GetSystemMetrics(SM_CYEDGE);
  1932. m_Toolbar = CreateWindowEx(0, REBARCLASSNAME, NULL,
  1933. WS_VISIBLE | WS_CHILD |
  1934. WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
  1935. CCS_NODIVIDER | CCS_NOPARENTALIGN |
  1936. RBS_VARHEIGHT | RBS_BANDBORDERS,
  1937. 0, 0, m_Size.cx, Height, m_Win,
  1938. (HMENU)ID_TOOLBAR,
  1939. g_hInst, NULL);
  1940. if (m_Toolbar == NULL)
  1941. {
  1942. return FALSE;
  1943. }
  1944. REBARINFO BarInfo;
  1945. BarInfo.cbSize = sizeof(BarInfo);
  1946. BarInfo.fMask = 0;
  1947. BarInfo.himl = NULL;
  1948. SendMessage(m_Toolbar, RB_SETBARINFO, 0, (LPARAM)&BarInfo);
  1949. m_ToolbarEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", NULL,
  1950. WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL,
  1951. 0, 0, 18 * m_Font->Metrics.tmAveCharWidth,
  1952. Height, m_Toolbar, (HMENU)IDC_EDIT_OFFSET,
  1953. g_hInst, NULL);
  1954. if (m_ToolbarEdit == NULL)
  1955. {
  1956. return FALSE;
  1957. }
  1958. SendMessage(m_ToolbarEdit, WM_SETFONT, (WPARAM)m_Font->Font, 0);
  1959. SendMessage(m_ToolbarEdit, EM_LIMITTEXT, sizeof(m_OffsetExpr) - 1, 0);
  1960. GetClientRect(m_ToolbarEdit, &Rect);
  1961. REBARBANDINFO BandInfo;
  1962. BandInfo.cbSize = sizeof(BandInfo);
  1963. BandInfo.fMask = RBBIM_STYLE | RBBIM_TEXT | RBBIM_CHILD | RBBIM_CHILDSIZE;
  1964. BandInfo.fStyle = RBBS_FIXEDSIZE;
  1965. BandInfo.lpText = "Offset:";
  1966. BandInfo.hwndChild = m_ToolbarEdit;
  1967. BandInfo.cxMinChild = Rect.right - Rect.left;
  1968. BandInfo.cyMinChild = Rect.bottom - Rect.top;
  1969. SendMessage(m_Toolbar, RB_INSERTBAND, -1, (LPARAM)&BandInfo);
  1970. // If the toolbar is allowed to shrink too small it hangs
  1971. // while resizing. Just let it clip off below a certain width.
  1972. m_MinToolbarWidth = BandInfo.cxMinChild * 2;
  1973. PSTR PrevText = "Previous";
  1974. m_PreviousButton =
  1975. AddButtonBand(m_Toolbar, PrevText, PrevText, IDC_DISASM_PREVIOUS);
  1976. m_NextButton =
  1977. AddButtonBand(m_Toolbar, "Next", PrevText, IDC_DISASM_NEXT);
  1978. if (m_PreviousButton == NULL || m_NextButton == NULL)
  1979. {
  1980. return FALSE;
  1981. }
  1982. // Maximize the space for the offset expression.
  1983. SendMessage(m_Toolbar, RB_MAXIMIZEBAND, 0, FALSE);
  1984. GetClientRect(m_Toolbar, &Rect);
  1985. m_ToolbarHeight = Rect.bottom - Rect.top;
  1986. m_ShowToolbar = TRUE;
  1987. if (!EDITWIN_DATA::OnCreate())
  1988. {
  1989. return FALSE;
  1990. }
  1991. // Suppress the scroll bar as the text is always
  1992. // fitted to the window size.
  1993. SendMessage(m_hwndChild, EM_SHOWSCROLLBAR, SB_VERT, FALSE);
  1994. SendMessage(m_hwndChild, EM_SETEVENTMASK, 0, ENM_KEYEVENTS);
  1995. return TRUE;
  1996. }
  1997. LRESULT
  1998. DISASMWIN_DATA::OnCommand(WPARAM Wpm, LPARAM Lpm)
  1999. {
  2000. switch(LOWORD(Wpm))
  2001. {
  2002. case IDC_EDIT_OFFSET:
  2003. if (HIWORD(Wpm) == EN_CHANGE)
  2004. {
  2005. // This message is sent on every keystroke
  2006. // which causes a bit too much updating.
  2007. // Set up a timer to trigger the actual
  2008. // update in half a second.
  2009. SetTimer(m_Win, IDC_EDIT_OFFSET, EDIT_DELAY, NULL);
  2010. m_UpdateExpr = TRUE;
  2011. }
  2012. break;
  2013. case IDC_DISASM_PREVIOUS:
  2014. ScrollLower();
  2015. break;
  2016. case IDC_DISASM_NEXT:
  2017. ScrollHigher();
  2018. break;
  2019. }
  2020. return 0;
  2021. }
  2022. void
  2023. DISASMWIN_DATA::OnSize(void)
  2024. {
  2025. EDITWIN_DATA::OnSize();
  2026. // Force buffer to refill for new line count.
  2027. UiRequestRead();
  2028. }
  2029. void
  2030. DISASMWIN_DATA::OnTimer(WPARAM TimerId)
  2031. {
  2032. if (TimerId == IDC_EDIT_OFFSET && m_UpdateExpr)
  2033. {
  2034. m_UpdateExpr = FALSE;
  2035. GetWindowText(m_ToolbarEdit, m_OffsetExpr, sizeof(m_OffsetExpr));
  2036. UiRequestRead();
  2037. }
  2038. }
  2039. LRESULT
  2040. DISASMWIN_DATA::OnNotify(WPARAM Wpm, LPARAM Lpm)
  2041. {
  2042. MSGFILTER* Filter = (MSGFILTER*)Lpm;
  2043. if (Filter->nmhdr.code != EN_MSGFILTER)
  2044. {
  2045. return EDITWIN_DATA::OnNotify(Wpm, Lpm);
  2046. }
  2047. if (Filter->msg == WM_KEYDOWN)
  2048. {
  2049. switch(Filter->wParam)
  2050. {
  2051. case VK_UP:
  2052. {
  2053. CHARRANGE range;
  2054. SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM) &range);
  2055. if (!SendMessage(m_hwndChild, EM_LINEFROMCHAR, range.cpMin, 0))
  2056. {
  2057. // up arrow on top line, scroll
  2058. ScrollLower();
  2059. return 1;
  2060. }
  2061. break;
  2062. }
  2063. case VK_DOWN:
  2064. {
  2065. CHARRANGE range;
  2066. int MaxLine;
  2067. SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM) &range);
  2068. MaxLine = (int) SendMessage(m_hwndChild, EM_GETLINECOUNT, 0, 0);
  2069. if (MaxLine == (1+SendMessage(m_hwndChild, EM_LINEFROMCHAR, range.cpMin, 0)))
  2070. {
  2071. // down arrow on bottom line, scroll
  2072. ScrollHigher();
  2073. return 1;
  2074. }
  2075. break;
  2076. }
  2077. case VK_PRIOR:
  2078. ScrollLower();
  2079. return 1;
  2080. case VK_NEXT:
  2081. ScrollHigher();
  2082. return 1;
  2083. }
  2084. }
  2085. else if (WM_SYSKEYDOWN == Filter->msg ||
  2086. WM_SYSKEYUP == Filter->msg ||
  2087. WM_SYSCHAR == Filter->msg)
  2088. {
  2089. // Force default processing for menu operations
  2090. // so that the Alt-minus menu comes up.
  2091. return 1;
  2092. }
  2093. return 0;
  2094. }
  2095. void
  2096. DISASMWIN_DATA::OnUpdate(UpdateType Type)
  2097. {
  2098. if (Type == UPDATE_BP ||
  2099. Type == UPDATE_END_SESSION)
  2100. {
  2101. UpdateBpMarks();
  2102. return;
  2103. }
  2104. else if (Type != UPDATE_BUFFER)
  2105. {
  2106. return;
  2107. }
  2108. HRESULT Status;
  2109. Status = UiLockForRead();
  2110. if (Status == S_OK)
  2111. {
  2112. PULONG64 LineMap;
  2113. ULONG Line;
  2114. if (!g_LineMarkers)
  2115. {
  2116. SendMessage(m_hwndChild, WM_SETTEXT,
  2117. 0, (LPARAM)m_Data + m_TextOffset);
  2118. }
  2119. else
  2120. {
  2121. SendMessage(m_hwndChild, WM_SETTEXT, 0, (LPARAM)"");
  2122. PSTR Text = (PSTR)m_Data + m_TextOffset;
  2123. for (;;)
  2124. {
  2125. SendMessage(m_hwndChild, EM_REPLACESEL, FALSE, (LPARAM)" ");
  2126. PSTR NewLine = strchr(Text, '\n');
  2127. if (NewLine != NULL)
  2128. {
  2129. *NewLine = 0;
  2130. }
  2131. SendMessage(m_hwndChild, EM_REPLACESEL, FALSE, (LPARAM)Text);
  2132. if (NewLine == NULL)
  2133. {
  2134. break;
  2135. }
  2136. SendMessage(m_hwndChild, EM_REPLACESEL, FALSE, (LPARAM)"\n");
  2137. *NewLine = '\n';
  2138. Text = NewLine + 1;
  2139. }
  2140. }
  2141. // Highlight the last line of multiline disassembly.
  2142. LineMap = (PULONG64)m_Data;
  2143. Line = m_PrimaryLine;
  2144. while (Line + 1 < m_TextLines &&
  2145. LineMap[Line] == DEBUG_INVALID_OFFSET)
  2146. {
  2147. Line++;
  2148. }
  2149. SetCurrentLineHighlight(Line);
  2150. UnlockStateBuffer(this);
  2151. RicheditUpdateColors(m_hwndChild,
  2152. g_Colors[COL_PLAIN_TEXT].Color, TRUE,
  2153. 0, FALSE);
  2154. UpdateCurrentLineHighlight();
  2155. UpdateBpMarks();
  2156. EnableWindow(m_PreviousButton, m_FirstInstr != m_PrimaryInstr);
  2157. EnableWindow(m_NextButton, m_LastInstr != m_PrimaryInstr);
  2158. }
  2159. else
  2160. {
  2161. SendLockStatusMessage(m_hwndChild, WM_SETTEXT, Status);
  2162. RemoveCurrentLineHighlight();
  2163. }
  2164. }
  2165. void
  2166. DISASMWIN_DATA::UpdateBpMarks(void)
  2167. {
  2168. if (m_TextLines == 0 ||
  2169. UiLockForRead() != S_OK)
  2170. {
  2171. return;
  2172. }
  2173. if (g_BpBuffer->UiLockForRead() != S_OK)
  2174. {
  2175. UnlockStateBuffer(this);
  2176. return;
  2177. }
  2178. SendMessage(m_hwndChild, WM_SETREDRAW, FALSE, 0);
  2179. // Remove existing BP highlights.
  2180. RemoveAllHighlights(EHL_ANY_BP);
  2181. //
  2182. // Highlight every line that matches a breakpoint.
  2183. //
  2184. PULONG64 LineMap = (PULONG64)m_Data;
  2185. BpBufferData* BpData = (BpBufferData*)g_BpBuffer->GetDataBuffer();
  2186. ULONG Line;
  2187. BpStateType State;
  2188. for (Line = 0; Line < m_TextLines; Line++)
  2189. {
  2190. if (*LineMap != DEBUG_INVALID_OFFSET)
  2191. {
  2192. State = IsBpAtOffset(BpData, *LineMap, NULL);
  2193. if (State != BP_NONE)
  2194. {
  2195. AddHighlight(Line, State == BP_ENABLED ?
  2196. EHL_ENABLED_BP : EHL_DISABLED_BP);
  2197. }
  2198. }
  2199. LineMap++;
  2200. }
  2201. SendMessage(m_hwndChild, WM_SETREDRAW, TRUE, 0);
  2202. InvalidateRect(m_hwndChild, NULL, TRUE);
  2203. UnlockStateBuffer(g_BpBuffer);
  2204. UnlockStateBuffer(this);
  2205. }
  2206. void
  2207. DISASMWIN_DATA::SetCurInstr(ULONG64 Offset)
  2208. {
  2209. // Any pending user update is now irrelevant.
  2210. m_UpdateExpr = FALSE;
  2211. sprintf(m_OffsetExpr, "0x%I64x", Offset);
  2212. // Force engine to update buffer.
  2213. UiRequestRead();
  2214. }
  2215. void
  2216. RicheditFind(HWND Edit,
  2217. PTSTR Text, ULONG Flags,
  2218. CHARRANGE* SaveSel, PULONG SaveFlags,
  2219. BOOL HideSel)
  2220. {
  2221. if (Text == NULL)
  2222. {
  2223. // Clear last find.
  2224. if (SaveSel->cpMax >= SaveSel->cpMin)
  2225. {
  2226. if (*SaveFlags & FR_DOWN)
  2227. {
  2228. SaveSel->cpMin = SaveSel->cpMax;
  2229. }
  2230. else
  2231. {
  2232. SaveSel->cpMax = SaveSel->cpMin;
  2233. }
  2234. if (HideSel)
  2235. {
  2236. SendMessage(Edit, EM_SETOPTIONS, ECOOP_AND, ~ECO_NOHIDESEL);
  2237. }
  2238. SendMessage(Edit, EM_EXSETSEL, 0, (LPARAM)SaveSel);
  2239. SendMessage(Edit, EM_SCROLLCARET, 0, 0);
  2240. SaveSel->cpMin = 1;
  2241. SaveSel->cpMax = 0;
  2242. }
  2243. }
  2244. else
  2245. {
  2246. LRESULT Match;
  2247. FINDTEXTEX Find;
  2248. SendMessage(Edit, EM_EXGETSEL, 0, (LPARAM)&Find.chrg);
  2249. if (Flags & FR_DOWN)
  2250. {
  2251. if (Find.chrg.cpMax > Find.chrg.cpMin)
  2252. {
  2253. Find.chrg.cpMin++;
  2254. }
  2255. Find.chrg.cpMax = LONG_MAX;
  2256. }
  2257. else
  2258. {
  2259. Find.chrg.cpMax = 0;
  2260. }
  2261. Find.lpstrText = Text;
  2262. Match = SendMessage(Edit, EM_FINDTEXTEX, Flags, (LPARAM)&Find);
  2263. if (Match != -1)
  2264. {
  2265. *SaveSel = Find.chrgText;
  2266. *SaveFlags = Flags;
  2267. if (HideSel)
  2268. {
  2269. SendMessage(Edit, EM_SETOPTIONS, ECOOP_OR, ECO_NOHIDESEL);
  2270. }
  2271. SendMessage(Edit, EM_EXSETSEL, 0, (LPARAM)SaveSel);
  2272. SendMessage(Edit, EM_SCROLLCARET, 0, 0);
  2273. }
  2274. else
  2275. {
  2276. if (g_FindDialog)
  2277. {
  2278. EnableWindow(g_FindDialog, FALSE);
  2279. }
  2280. InformationBox(ERR_No_More_Matches, Text);
  2281. if (g_FindDialog)
  2282. {
  2283. EnableWindow(g_FindDialog, TRUE);
  2284. SetFocus(g_FindDialog);
  2285. }
  2286. }
  2287. }
  2288. }
  2289. DWORD CALLBACK
  2290. StreamOutCb(DWORD_PTR File, LPBYTE Buffer, LONG Request, PLONG Done)
  2291. {
  2292. return WriteFile((HANDLE)File, Buffer, Request, (LPDWORD)Done, NULL) ?
  2293. 0 : GetLastError();
  2294. }
  2295. HRESULT
  2296. RicheditWriteToFile(HWND Edit, HANDLE File)
  2297. {
  2298. EDITSTREAM Stream;
  2299. Stream.dwCookie = (DWORD_PTR)File;
  2300. Stream.dwError = 0;
  2301. Stream.pfnCallback = StreamOutCb;
  2302. SendMessage(Edit, EM_STREAMOUT, SF_TEXT, (LPARAM)&Stream);
  2303. if (Stream.dwError)
  2304. {
  2305. return HRESULT_FROM_WIN32(Stream.dwError);
  2306. }
  2307. return S_OK;
  2308. }
  2309. void
  2310. RicheditUpdateColors(HWND Edit,
  2311. COLORREF Fg, BOOL UpdateFg,
  2312. COLORREF Bg, BOOL UpdateBg)
  2313. {
  2314. if (UpdateBg)
  2315. {
  2316. if (UpdateFg)
  2317. {
  2318. SendMessage(Edit, WM_SETREDRAW, FALSE, 0);
  2319. }
  2320. SendMessage(Edit, EM_SETBKGNDCOLOR, FALSE, Bg);
  2321. if (UpdateFg)
  2322. {
  2323. SendMessage(Edit, WM_SETREDRAW, TRUE, 0);
  2324. }
  2325. }
  2326. if (UpdateFg)
  2327. {
  2328. CHARFORMAT2 Fmt;
  2329. ZeroMemory(&Fmt, sizeof(Fmt));
  2330. Fmt.cbSize = sizeof(Fmt);
  2331. Fmt.dwMask = CFM_COLOR;
  2332. Fmt.crTextColor = Fg;
  2333. SendMessage(Edit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&Fmt);
  2334. }
  2335. }
  2336. #define EXTRA_VIS 3
  2337. void
  2338. RicheditScrollToLine(HWND Edit, ULONG Line, ULONG VisLines)
  2339. {
  2340. CHARRANGE Sel;
  2341. ULONG CurLine;
  2342. ULONG VisAround;
  2343. ULONG TotalLines;
  2344. LONG Scroll;
  2345. //
  2346. // Scroll the given line into view. Try to keep
  2347. // the line from being the first or last line
  2348. // in view.
  2349. //
  2350. // Disable the window during this to prevent
  2351. // the default richedit scrolling from occurring.
  2352. //
  2353. VisAround = VisLines / 2;
  2354. if (VisAround > EXTRA_VIS)
  2355. {
  2356. VisAround = EXTRA_VIS;
  2357. }
  2358. TotalLines = (ULONG)SendMessage(Edit, EM_GETLINECOUNT, 0, 0);
  2359. CurLine = (ULONG)SendMessage(Edit, EM_GETFIRSTVISIBLELINE, 0, 0);
  2360. if (Line < CurLine + VisAround)
  2361. {
  2362. Scroll = (LONG)Line - (LONG)(CurLine + VisAround);
  2363. if ((ULONG)-Scroll > CurLine)
  2364. {
  2365. Scroll = -(LONG)CurLine;
  2366. }
  2367. }
  2368. else if (Line >= CurLine + VisLines - VisAround &&
  2369. CurLine + VisLines < TotalLines)
  2370. {
  2371. Scroll = (LONG)Line - (LONG)(CurLine + VisLines - VisAround) + 1;
  2372. }
  2373. else
  2374. {
  2375. Scroll = 0;
  2376. }
  2377. if (Scroll)
  2378. {
  2379. SendMessage(Edit, EM_LINESCROLL, 0, Scroll);
  2380. }
  2381. Sel.cpMax = Sel.cpMin = (LONG)
  2382. SendMessage(Edit, EM_LINEINDEX, Line, 0);
  2383. SendMessage(Edit, EM_EXSETSEL, 0, (LPARAM)&Sel);
  2384. }
  2385. ULONG
  2386. RicheditGetSelectionText(HWND Edit, PTSTR Buffer, ULONG BufferChars)
  2387. {
  2388. CHARRANGE Sel;
  2389. SendMessage(Edit, EM_EXGETSEL, 0, (LPARAM)&Sel);
  2390. if (Sel.cpMin >= Sel.cpMax)
  2391. {
  2392. return 0;
  2393. }
  2394. Sel.cpMax -= Sel.cpMin;
  2395. if ((ULONG)Sel.cpMax + 1 > BufferChars)
  2396. {
  2397. return 0;
  2398. }
  2399. SendMessage(Edit, EM_GETSELTEXT, 0, (LPARAM)Buffer);
  2400. return Sel.cpMax;
  2401. }
  2402. ULONG
  2403. RicheditGetSourceToken(HWND Edit, PTSTR Buffer, ULONG BufferChars,
  2404. CHARRANGE* Range)
  2405. {
  2406. LRESULT Idx;
  2407. TEXTRANGE GetRange;
  2408. CHARRANGE Sel;
  2409. //
  2410. // Get the text for the line containing the selection.
  2411. //
  2412. SendMessage(Edit, EM_EXGETSEL, 0, (LPARAM)&Sel);
  2413. if (Sel.cpMin > Sel.cpMax)
  2414. {
  2415. return 0;
  2416. }
  2417. if ((Idx = SendMessage(Edit, EM_LINEINDEX, -1, 0)) < 0)
  2418. {
  2419. return 0;
  2420. }
  2421. GetRange.chrg.cpMin = (LONG)Idx;
  2422. if (!(Idx = SendMessage(Edit, EM_LINELENGTH, GetRange.chrg.cpMin, 0)))
  2423. {
  2424. return 0;
  2425. }
  2426. if (BufferChars <= (ULONG)Idx)
  2427. {
  2428. Idx = (LONG)BufferChars - 1;
  2429. }
  2430. GetRange.chrg.cpMax = GetRange.chrg.cpMin + (LONG)Idx;
  2431. GetRange.lpstrText = Buffer;
  2432. if (!SendMessage(Edit, EM_GETTEXTRANGE, 0, (LPARAM)&GetRange))
  2433. {
  2434. return 0;
  2435. }
  2436. //
  2437. // Check and see if the selection is within a source token.
  2438. //
  2439. PTSTR Scan = Buffer + (Sel.cpMin - GetRange.chrg.cpMin);
  2440. if (!iscsym(*Scan))
  2441. {
  2442. return 0;
  2443. }
  2444. //
  2445. // Find the start of the token and validate it.
  2446. //
  2447. PTSTR Start = Scan;
  2448. if (Start > Buffer)
  2449. {
  2450. while (--Start >= Buffer && iscsym(*Start))
  2451. {
  2452. // Back up.
  2453. }
  2454. Start++;
  2455. }
  2456. if (!iscsymf(*Start))
  2457. {
  2458. return 0;
  2459. }
  2460. //
  2461. // Find the end of the token.
  2462. //
  2463. Scan++;
  2464. while (iscsym(*Scan))
  2465. {
  2466. Scan++;
  2467. }
  2468. ULONG Len;
  2469. // Chop the buffer down to just the token and return.
  2470. Len = (ULONG)(Scan - Start);
  2471. memmove(Buffer, Start, Len);
  2472. Buffer[Len] = 0;
  2473. Range->cpMin = GetRange.chrg.cpMin + (LONG)(Start - Buffer);
  2474. Range->cpMax = Range->cpMin + Len;
  2475. return Len;
  2476. }
  2477. #undef DEFINE_GET_WINDATA
  2478. #undef ASSERT_CLASS_TYPE
  2479. #ifndef DBG
  2480. #define ASSERT_CLASS_TYPE(p, ct) ((VOID)0)
  2481. #else
  2482. #define ASSERT_CLASS_TYPE(p, ct) if (p) { AssertType(*p, ct); }
  2483. #endif
  2484. #define DEFINE_GET_WINDATA(ClassType, FuncName) \
  2485. ClassType * \
  2486. Get##FuncName##WinData( \
  2487. HWND hwnd \
  2488. ) \
  2489. { \
  2490. ClassType *p = (ClassType *) \
  2491. GetWindowLongPtr(hwnd, GWLP_USERDATA); \
  2492. \
  2493. ASSERT_CLASS_TYPE(p, ClassType); \
  2494. \
  2495. return p; \
  2496. }
  2497. #include "fncdefs.h"
  2498. #undef DEFINE_GET_WINDATA
  2499. #undef ASSERT_CLASS_TYPE