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

1814 lines
42 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Zippy Main Window
  5. Abstract:
  6. This class implements the main window for zippy as well as controlling
  7. its child windows.
  8. Author:
  9. Marc Reyhner 8/28/2000
  10. --*/
  11. #include "stdafx.h"
  12. #include "ZippyWindow.h"
  13. #include "resource.h"
  14. #include "eZippy.h"
  15. #include "richedit.h"
  16. #include "ModalDialog.h"
  17. #include "TraceManager.h"
  18. #include "OptionsDialog.h"
  19. BOOL CZippyWindow::gm_Inited = FALSE;
  20. ATOM CZippyWindow::gm_Atom = NULL;
  21. UINT CZippyWindow::gm_FindMessageStringMsg = 0;
  22. static DWORD CALLBACK SaveCallback(DWORD_PTR dwCookie,LPBYTE pbBuff,LONG cb,LONG *pcb);
  23. #define TRC_PROC_FMT _T("%04.4lx")
  24. #define SAVE_FILE_TYPE _T("Text Files (*.txt)\0*.txt\0")
  25. #define SAVE_FILE_EXTENSION _T("txt")
  26. #define SAVE_CONF_FILE_TYPE _T("Trace Configuration Files (*.tcf)\0*.tcf\0")
  27. #define SAVE_CONF_FILE_EXTENSION _T("tcf")
  28. #define NUM_COLORS 15
  29. #define APPENDMUTEXNAME _T("Local\\MicrosoftTerminalServerTraceViewerAppendMutex")
  30. #define ZIPPY_WINDOW_POS_VALUE _T("WindowPosition")
  31. #define WINDOW_DEF_TOP 50
  32. #define WINDOW_DEF_BOTTOM 530
  33. #define WINDOW_DEF_RIGHT 690
  34. #define WINDOW_DEF_LEFT 50
  35. // We use an 80 character buffer for find
  36. // and replace operations.
  37. #define FIND_REPLACE_BUFFER_SIZE 80
  38. // This list of colors we cycle through. Note if you change this
  39. // list you need to update NUM_COLORS to the new count.
  40. static COLORREF colors[NUM_COLORS] = {
  41. RGB(153,51,0), /* Brown */
  42. RGB(0,51,102), /* Dark Teal */
  43. RGB(51,51,153), /* Indigo */
  44. RGB(128,0,0), /* Dark Red */
  45. RGB(255,102,0), /* Orange */
  46. RGB(0,128,0), /* Green */
  47. RGB(0,0,255), /* Blue */
  48. RGB(255,0,0), /* Red */
  49. RGB(51,204,204),/* Acqua */
  50. RGB(128,0,128), /* Violet */
  51. RGB(255,0,255), /* Pink */
  52. RGB(255,255,0), /* Yellow */
  53. RGB(0,255,0), /* Bright Green */
  54. RGB(0,255,255), /* Turquoise */
  55. RGB(204,153,255)/* Lavender */
  56. };
  57. //
  58. // *** Public Class Members ***
  59. //
  60. CZippyWindow::CZippyWindow(
  61. )
  62. /*++
  63. Routine Description:
  64. The constructor simply initializes the class variables.
  65. Arguments:
  66. None
  67. Return value:
  68. None
  69. --*/
  70. {
  71. m_bIsTracing = TRUE;
  72. m_bIsStoringTraceData = FALSE;
  73. ZeroMemory(m_threadHistory,sizeof(m_threadHistory));
  74. m_nextThreadIndex = 0;
  75. m_nextThreadColor = 0;
  76. m_lastProcessId = 0;
  77. m_LastLogEndedInNewLine = TRUE;
  78. m_hWnd = NULL;
  79. m_hStatusWnd = NULL;
  80. m_hControlWnd = NULL;
  81. m_hWndFindReplace = NULL;
  82. m_lpSavedOutputStart = NULL;
  83. m_lpSavedOutputTail = NULL;
  84. ZeroMemory(&m_FindReplace,sizeof(m_FindReplace));
  85. ZeroMemory(m_SaveFile,sizeof(m_SaveFile));
  86. ZeroMemory(m_SaveConfFile,sizeof(m_SaveConfFile));
  87. ZeroMemory(m_LoadConfFile,sizeof(m_LoadConfFile));
  88. }
  89. CZippyWindow::~CZippyWindow(
  90. )
  91. /*++
  92. Routine Description:
  93. Cleans up any dynamicly allocated memory,
  94. Arguments:
  95. None
  96. Return value:
  97. None
  98. --*/
  99. {
  100. if (m_FindReplace.lpstrFindWhat) {
  101. HeapFree(GetProcessHeap(),0,m_FindReplace.lpstrFindWhat);
  102. }
  103. if (m_FindReplace.lpstrReplaceWith) {
  104. HeapFree(GetProcessHeap(),0,m_FindReplace.lpstrReplaceWith);
  105. }
  106. }
  107. DWORD CZippyWindow::Create(
  108. IN CTraceManager *rTracer
  109. )
  110. /*++
  111. Routine Description:
  112. Actually creates the zippy window.
  113. Arguments:
  114. rTracer - A pointer to the trace manager
  115. Return value:
  116. 0 - Success
  117. Non zero - An error occurred creating the window
  118. --*/
  119. {
  120. DWORD dwResult;
  121. DWORD dwWindowStyleEx;
  122. DWORD dwWindowStyle;
  123. TCHAR wndTitle[MAX_STR_LEN];
  124. RECT wndRect;
  125. m_rTracer = rTracer;
  126. if (!gm_Inited) {
  127. dwResult = _InitClassStaticMembers();
  128. if (dwResult != ERROR_SUCCESS) {
  129. return dwResult;
  130. }
  131. }
  132. m_hAppendMutex = CreateMutex(NULL,FALSE,APPENDMUTEXNAME);
  133. m_FindReplace.lStructSize = sizeof(m_FindReplace);
  134. m_FindReplace.lpstrFindWhat = (LPTSTR)HeapAlloc(GetProcessHeap(),
  135. HEAP_ZERO_MEMORY,FIND_REPLACE_BUFFER_SIZE*sizeof(TCHAR));
  136. if (!m_FindReplace.lpstrFindWhat) {
  137. return GetLastError();
  138. }
  139. m_FindReplace.lpstrReplaceWith = (LPTSTR)HeapAlloc(GetProcessHeap(),
  140. HEAP_ZERO_MEMORY,FIND_REPLACE_BUFFER_SIZE*sizeof(TCHAR));
  141. if (!m_FindReplace.lpstrReplaceWith) {
  142. return GetLastError();
  143. }
  144. LoadStringSimple(IDS_ZIPPYWINDOWTITLE,wndTitle);
  145. GetSavedWindowPos(&wndRect);
  146. dwWindowStyleEx = WS_EX_WINDOWEDGE;
  147. dwWindowStyle = WS_OVERLAPPEDWINDOW|WS_CLIPSIBLINGS|WS_VISIBLE;
  148. m_hWnd = CreateWindowEx(dwWindowStyleEx, (LPTSTR)gm_Atom, wndTitle,
  149. dwWindowStyle, wndRect.left, wndRect.top, wndRect.right,
  150. wndRect.bottom,NULL,NULL,g_hInstance,this);
  151. if (!m_hWnd) {
  152. return GetLastError();
  153. }
  154. return ERROR_SUCCESS;
  155. }
  156. VOID
  157. CZippyWindow::AppendTextToWindow(
  158. IN DWORD processID,
  159. IN LPCTSTR text,
  160. IN UINT len
  161. )
  162. /*++
  163. Routine Description:
  164. Appends new trace data to the end of the rich edit contrl
  165. Arguments:
  166. processID - Process ID of the process sending the debug string
  167. text - The data sent via OutputDebugString
  168. len - Length of the data
  169. Return value:
  170. None
  171. --*/
  172. {
  173. UINT controlTextLength;
  174. CHARRANGE newSel;
  175. BOOL computeColor;
  176. BOOL setNewColor;
  177. CHARFORMAT newFormat;
  178. LPSAVEDOUTPUT lpSave;
  179. if (!m_bIsTracing) {
  180. return;
  181. }
  182. WaitForSingleObject(m_hAppendMutex,INFINITE);
  183. if (m_bIsStoringTraceData) {
  184. // This is kinda sketchy but what we do is to allocate room for the string
  185. // at the end of the structure. There shouldn't be any alignment problems
  186. // since we need to align on a short and the structure has no items
  187. // to get that off.
  188. lpSave = (LPSAVEDOUTPUT)HeapAlloc(GetProcessHeap(),0,sizeof(SAVEDOUTPUT) +
  189. (sizeof(TCHAR) * (len+1)));
  190. if (!lpSave) {
  191. // eom error?
  192. goto CLEANUP_AND_EXIT;
  193. }
  194. lpSave->procID = processID;
  195. lpSave->text = (LPTSTR)((BYTE)lpSave + sizeof(SAVEDOUTPUT));
  196. _tcscpy(lpSave->text,text);
  197. lpSave->len = len;
  198. lpSave->next = NULL;
  199. if (!m_lpSavedOutputTail) {
  200. m_lpSavedOutputStart = lpSave;
  201. } else {
  202. m_lpSavedOutputTail->next = lpSave;
  203. }
  204. m_lpSavedOutputTail = lpSave;
  205. goto CLEANUP_AND_EXIT;
  206. }
  207. if (m_lastProcessId != processID ||
  208. m_LastLogEndedInNewLine) {
  209. computeColor = TRUE;
  210. } else {
  211. computeColor = FALSE;
  212. }
  213. setNewColor = ComputeNewColor(processID,text,len,&newFormat);
  214. m_LastLogEndedInNewLine = (text[len-1] == '\n') ? TRUE : FALSE;
  215. m_lastProcessId = processID;
  216. controlTextLength = (UINT)SendMessage(m_hControlWnd,WM_GETTEXTLENGTH,0,0);
  217. newSel.cpMin = controlTextLength;
  218. newSel.cpMax = controlTextLength+1;
  219. // set the new text
  220. SendMessage(m_hControlWnd,EM_EXSETSEL,0,(LPARAM)&newSel);
  221. if (setNewColor) {
  222. SendMessage(m_hControlWnd,EM_SETCHARFORMAT,SCF_SELECTION,(LPARAM)&newFormat);
  223. }
  224. SendMessage(m_hControlWnd,EM_REPLACESEL,0,(LPARAM)text);
  225. CLEANUP_AND_EXIT:
  226. ReleaseMutex(m_hAppendMutex);
  227. }
  228. VOID
  229. CZippyWindow::LoadConfFile(
  230. IN LPTSTR confFile
  231. )
  232. /*++
  233. Routine Description:
  234. This sets the tracing configuration using the given file
  235. Arguments:
  236. confFile - File containing the tracing configuration
  237. Return value:
  238. None
  239. --*/
  240. {
  241. _tcscpy(m_LoadConfFile,confFile);
  242. DoLoadConfInternal();
  243. }
  244. BOOL
  245. CZippyWindow::IsDialogMessage(
  246. IN LPMSG lpMsg
  247. )
  248. /*++
  249. Routine Description:
  250. This calls IsDialogMessage on any non modal dialogs that this window
  251. is hosting to see if the message is for them
  252. Arguments:
  253. lpMsg - Message to check if it is a dialog message
  254. Return value:
  255. TRUE - The message did belong to a dialog
  256. FALSE - The message did not belong to a dialog
  257. --*/
  258. {
  259. if (IsWindow(m_hWndFindReplace)) {
  260. // The :: below is necessary to make it use the Win32 function
  261. // not our method
  262. return ::IsDialogMessage(m_hWndFindReplace,lpMsg);
  263. }
  264. return FALSE;
  265. }
  266. INT WINAPI
  267. CZippyWindow::TranslateAccelerator(
  268. IN HACCEL hAccTable,
  269. IN LPMSG lpMsg
  270. )
  271. /*++
  272. Routine Description:
  273. This calls the win32 TranslateAccelerator to determine
  274. if the given message is an accelerator for this window
  275. Arguments:
  276. hAccTable - Accelerator table to use
  277. lpMsg - Message to check
  278. Return value:
  279. See Win32 TranslateAccelerator documentation
  280. --*/
  281. {
  282. // :: Necessary to get the win32 call.
  283. return ::TranslateAccelerator(m_hWnd,hAccTable,lpMsg);
  284. }
  285. //
  286. // *** Private Class Members ***
  287. //
  288. // static members
  289. DWORD
  290. CZippyWindow::_InitClassStaticMembers(
  291. )
  292. /*++
  293. Routine Description:
  294. Creates the window class for zippy and registers
  295. for the FINDMSGSTRING windows message
  296. Arguments:
  297. None
  298. Return value:
  299. 0 - Success
  300. Non zero - Win32 error code
  301. --*/
  302. {
  303. WNDCLASS wndClass;
  304. HMODULE hLibrary;
  305. // We want to load RichEdit for the lifetime of our app.
  306. hLibrary = LoadLibrary(_T("Riched20.dll"));
  307. if (!hLibrary) {
  308. return GetLastError();
  309. }
  310. ZeroMemory(&wndClass,sizeof(wndClass));
  311. wndClass.style = CS_PARENTDC;
  312. wndClass.lpfnWndProc = _WindowProc;
  313. wndClass.hInstance = g_hInstance;
  314. wndClass.hIcon = (HICON)LoadImage(g_hInstance,MAKEINTRESOURCE(IDI_MAINFRAME),
  315. IMAGE_ICON,0,0,LR_SHARED);
  316. wndClass.hbrBackground = (HBRUSH)COLOR_WINDOWFRAME;
  317. wndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU);
  318. wndClass.lpszClassName = _T("ZippyWindowClass");
  319. gm_Atom = RegisterClass(&wndClass);
  320. if (!gm_Atom) {
  321. return GetLastError();
  322. }
  323. gm_FindMessageStringMsg = RegisterWindowMessage(FINDMSGSTRING);
  324. if (!gm_FindMessageStringMsg) {
  325. return GetLastError();
  326. }
  327. gm_Inited = TRUE;
  328. return ERROR_SUCCESS;
  329. }
  330. LRESULT CALLBACK
  331. CZippyWindow::_WindowProc(
  332. IN HWND hWnd,
  333. IN UINT uMsg,
  334. IN WPARAM wParam,
  335. IN LPARAM lParam)
  336. /*++
  337. Routine Description:
  338. Static version of the window proc. On WM_CREATE it calls OnCreate,
  339. otherwise it calls the non-static window proc
  340. Arguments:
  341. See Win32 Window Proc docs
  342. Return value:
  343. Message specific. See individual handlers for detail.
  344. --*/
  345. {
  346. CZippyWindow *theClass;
  347. if (uMsg == WM_CREATE) {
  348. SetLastError(0);
  349. theClass = (CZippyWindow *)((LPCREATESTRUCT)lParam)->lpCreateParams;
  350. SetWindowLongPtr(hWnd,GWLP_USERDATA,(LONG_PTR)theClass);
  351. if (GetLastError()) {
  352. return -1;
  353. }
  354. return theClass->OnCreate(hWnd);
  355. }
  356. theClass = (CZippyWindow*)GetWindowLongPtr(hWnd,GWLP_USERDATA);
  357. if (theClass) {
  358. return theClass->WindowProc(hWnd,uMsg,wParam,lParam);
  359. } else {
  360. return DefWindowProc(hWnd,uMsg,wParam,lParam);
  361. }
  362. }
  363. LRESULT CALLBACK
  364. CZippyWindow::WindowProc(
  365. IN HWND hWnd,
  366. IN UINT uMsg,
  367. IN WPARAM wParam,
  368. IN LPARAM lParam)
  369. /*++
  370. Routine Description:
  371. Non-static window proc. Either calls the default window proc or
  372. refers to the individual message handlers
  373. Arguments:
  374. See Win32 Window Proc docs
  375. Return value:
  376. Message specific. See individual handlers for detail.
  377. --*/
  378. {
  379. LRESULT retCode = 0;
  380. switch (uMsg) {
  381. case WM_COMMAND:
  382. OnCommand(wParam,lParam);
  383. break;
  384. case WM_SETFOCUS:
  385. OnSetFocus();
  386. break;
  387. case WM_SIZE:
  388. OnSize(LOWORD(lParam),HIWORD(lParam));
  389. break;
  390. case WM_INITMENUPOPUP:
  391. OnInitMenuPopup(wParam,lParam);
  392. break;
  393. case WM_MENUSELECT:
  394. OnMenuSelect(wParam,lParam);
  395. break;
  396. case WM_CLOSE:
  397. OnClose();
  398. break;
  399. case WM_DESTROY:
  400. OnDestroy();
  401. break;
  402. default:
  403. if (uMsg == gm_FindMessageStringMsg) {
  404. OnFindMessageString(lParam);
  405. } else {
  406. retCode = DefWindowProc(hWnd,uMsg,wParam,lParam);
  407. }
  408. break;
  409. }
  410. return retCode;
  411. }
  412. LRESULT
  413. CZippyWindow::OnCreate(
  414. IN HWND hWnd
  415. )
  416. /*++
  417. Routine Description:
  418. Creates the child windows and sets their initial parameters
  419. Arguments:
  420. hWnd - Pointer to the new main window
  421. Return value:
  422. 0 - Window was created
  423. -1 - Error occurred
  424. --*/
  425. {
  426. DWORD dwStyle;
  427. CHARFORMAT charFormat;
  428. TCHAR readyString[MAX_STR_LEN];
  429. dwStyle = WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL|ES_SUNKEN|
  430. ES_MULTILINE|ES_LEFT|ES_AUTOHSCROLL|ES_AUTOVSCROLL|ES_NOHIDESEL;
  431. m_hControlWnd = CreateWindow(RICHEDIT_CLASS,_T(""),
  432. dwStyle,0,0,0,0,hWnd,NULL,g_hInstance,NULL);
  433. if (!m_hControlWnd) {
  434. return -1;
  435. }
  436. dwStyle = SBARS_SIZEGRIP|WS_CHILD|WS_VISIBLE;
  437. m_hStatusWnd = CreateWindow(STATUSCLASSNAME,NULL,dwStyle,0,0,0,0,hWnd,NULL,
  438. g_hInstance,NULL);
  439. if (!m_hStatusWnd) {
  440. return -1;
  441. }
  442. LoadStringSimple(IDS_STATUSBARREADY,readyString);
  443. SendMessage(m_hStatusWnd,SB_SETTEXT,0|SBT_NOBORDERS,(LPARAM)readyString);
  444. charFormat.cbSize = sizeof(charFormat);
  445. charFormat.dwMask = CFM_FACE|CFM_SIZE;
  446. charFormat.yHeight = ZIPPY_FONT_SIZE*20;
  447. _tcscpy(charFormat.szFaceName,ZIPPY_FONT);
  448. // 4 billion characters should be a large enough limit...
  449. SendMessage(m_hControlWnd,EM_EXLIMITTEXT,0,0xFFFFFFFF);
  450. SendMessage(m_hControlWnd,EM_SETCHARFORMAT,SCF_ALL,(LPARAM)&charFormat);
  451. SendMessage(m_hControlWnd,EM_SETMODIFY,FALSE,0);
  452. SendMessage(m_hControlWnd,EM_EMPTYUNDOBUFFER,0,0);
  453. return 0;
  454. }
  455. VOID
  456. CZippyWindow::OnMenuSelect(
  457. IN WPARAM wParam,
  458. IN LPARAM lParam
  459. )
  460. /*++
  461. Routine Description:
  462. Sets the help string in the status bar for the selected menu.
  463. Arguments:
  464. wParam - menu itemid (LOWORD) and flags (HIWORD)
  465. lParam - menu handle
  466. Return value:
  467. None
  468. --*/
  469. {
  470. UINT item;
  471. UINT flags;
  472. HMENU hMenu;
  473. TCHAR statusMessage[MAX_STR_LEN];
  474. item = LOWORD(wParam);
  475. flags = HIWORD(wParam);
  476. hMenu = (HMENU)lParam;
  477. if (!item && flags == 0xFFFF) {
  478. // the menu was closed. Go back to the ready string.
  479. LoadStringSimple(IDS_STATUSBARREADY,statusMessage);
  480. SendMessage(m_hStatusWnd,SB_SETTEXT,0|SBT_NOBORDERS,(LPARAM)statusMessage);
  481. return;
  482. }
  483. if (flags & MF_POPUP) {
  484. statusMessage[0] = 0;
  485. } else if (!LoadStringSimple(item,statusMessage)) {
  486. // if we can't find the help string use the empty string.
  487. statusMessage[0] = 0;
  488. }
  489. SendMessage(m_hStatusWnd,SB_SETTEXT,0|SBT_NOBORDERS,(LPARAM)statusMessage);
  490. }
  491. VOID
  492. CZippyWindow::OnSize(
  493. IN INT width,
  494. IN INT height
  495. )
  496. /*++
  497. Routine Description:
  498. Resizes client windows to reflect the new size of the main window
  499. Arguments:
  500. width - New width of the client area
  501. height - New height of the client area
  502. Return value:
  503. None
  504. --*/
  505. {
  506. RECT statusBarArea;
  507. UINT statusBarHeight;
  508. RECT wndRect;
  509. if (!(width==0&&height==0)) {
  510. if (GetWindowRect(m_hWnd,&wndRect)) {
  511. SaveWindowPos(&wndRect);
  512. }
  513. }
  514. if (IsWindowVisible(m_hStatusWnd)) {
  515. GetWindowRect(m_hStatusWnd,&statusBarArea);
  516. statusBarHeight = statusBarArea.bottom - statusBarArea.top;
  517. SetWindowPos(m_hControlWnd,NULL,0,0,width,height-statusBarHeight,SWP_NOZORDER);
  518. // the status bar autosizes. We just need to tell it that it should
  519. SetWindowPos(m_hStatusWnd,NULL,0,0,0,0,SWP_NOZORDER);
  520. } else {
  521. SetWindowPos(m_hControlWnd,NULL,0,0,width,height,SWP_NOZORDER);
  522. }
  523. }
  524. VOID
  525. CZippyWindow::OnSetFocus(
  526. )
  527. /*++
  528. Routine Description:
  529. When we get focus we kick it down to the rich edit control
  530. Arguments:
  531. None
  532. Return value:
  533. None
  534. --*/
  535. {
  536. SetFocus(m_hControlWnd);
  537. }
  538. VOID
  539. CZippyWindow::OnInitMenuPopup(
  540. IN WPARAM wParam,
  541. IN LPARAM lParam
  542. )
  543. /*++
  544. Routine Description:
  545. When the user opens the menus we need to specify
  546. which are disabled and which are checked. Note that
  547. the menu id's are hard coded. I've commented which
  548. corespond to which for the switch statement
  549. Arguments:
  550. wParam - The menu handle
  551. lParam - (loword) the menu item id
  552. Return value:
  553. None
  554. --*/
  555. {
  556. HMENU hMenu;
  557. WORD item;
  558. item = LOWORD(lParam);
  559. hMenu = (HMENU)wParam;
  560. switch (item) {
  561. case 1: // Edit Menu
  562. UINT canUndo;
  563. UINT canRedo;
  564. UINT cutCopyEnabled;
  565. UINT pasteEnabled;
  566. UINT selectAllEnabled;
  567. UINT findEnabled;
  568. UINT findNextEnabled;
  569. UINT replaceEnabled;
  570. LRESULT textLength;
  571. CHARRANGE selRegion;
  572. if (SendMessage(m_hControlWnd,EM_CANUNDO,0,0)) {
  573. canUndo = MF_ENABLED;
  574. } else {
  575. canUndo = MF_GRAYED;
  576. }
  577. if (SendMessage(m_hControlWnd,EM_CANREDO,0,0)) {
  578. canRedo = MF_ENABLED;
  579. } else {
  580. canRedo = MF_GRAYED;
  581. }
  582. textLength = SendMessage(m_hControlWnd,WM_GETTEXTLENGTH,0,0);
  583. if (textLength == 0) {
  584. selectAllEnabled = MF_GRAYED;
  585. findEnabled = MF_GRAYED;
  586. findNextEnabled = MF_GRAYED;
  587. replaceEnabled = MF_GRAYED;
  588. } else {
  589. selectAllEnabled = MF_ENABLED;
  590. findEnabled = MF_ENABLED;
  591. replaceEnabled = MF_ENABLED;
  592. if (m_FindReplace.lpstrFindWhat[0] != 0) {
  593. findNextEnabled = MF_ENABLED;
  594. } else {
  595. findNextEnabled = MF_GRAYED;
  596. }
  597. }
  598. SendMessage(m_hControlWnd,EM_EXGETSEL,0,(LPARAM)&selRegion);
  599. if (selRegion.cpMax == selRegion.cpMin) {
  600. cutCopyEnabled = MF_GRAYED;
  601. } else {
  602. cutCopyEnabled = MF_ENABLED;
  603. // override select all since they selected the next character
  604. // to be typed
  605. selectAllEnabled = MF_ENABLED;
  606. }
  607. if (SendMessage(m_hControlWnd,EM_CANPASTE,0,0)) {
  608. pasteEnabled = MF_ENABLED;
  609. } else {
  610. pasteEnabled = MF_GRAYED;
  611. }
  612. EnableMenuItem(hMenu,ID_EDIT_UNDO,MF_BYCOMMAND|canUndo);
  613. EnableMenuItem(hMenu,ID_EDIT_REDO,MF_BYCOMMAND|canRedo);
  614. EnableMenuItem(hMenu,ID_EDIT_CUT,MF_BYCOMMAND|cutCopyEnabled);
  615. EnableMenuItem(hMenu,ID_EDIT_COPY,MF_BYCOMMAND|cutCopyEnabled);
  616. EnableMenuItem(hMenu,ID_EDIT_PASTE,MF_BYCOMMAND|pasteEnabled);
  617. EnableMenuItem(hMenu,ID_EDIT_SELECTALL,MF_BYCOMMAND|selectAllEnabled);
  618. EnableMenuItem(hMenu,ID_EDIT_FIND,MF_BYCOMMAND|findEnabled);
  619. EnableMenuItem(hMenu,ID_EDIT_FINDNEXT,MF_BYCOMMAND|findNextEnabled);
  620. EnableMenuItem(hMenu,ID_EDIT_REPLACE,MF_BYCOMMAND|replaceEnabled);
  621. break;
  622. case 2: // View Menu
  623. UINT statusBarChecked;
  624. if (IsWindowVisible(m_hStatusWnd)) {
  625. statusBarChecked = MF_CHECKED;
  626. } else {
  627. statusBarChecked = MF_UNCHECKED;
  628. }
  629. CheckMenuItem(hMenu,ID_VIEW_STATUSBAR,MF_BYCOMMAND|statusBarChecked);
  630. break;
  631. case 3: // Monitoring Menu
  632. UINT startActivated;
  633. UINT stopActivated;
  634. if (m_bIsTracing) {
  635. startActivated = MF_GRAYED;
  636. stopActivated = MF_ENABLED;
  637. } else {
  638. startActivated = MF_ENABLED;
  639. stopActivated = MF_GRAYED;
  640. }
  641. EnableMenuItem(hMenu,ID_MONITORING_START,MF_BYCOMMAND|startActivated);
  642. EnableMenuItem(hMenu,ID_MONITORING_STOP,MF_BYCOMMAND|stopActivated);
  643. // record is activated when stop is.
  644. EnableMenuItem(hMenu,ID_MONITORING_RECORD,MF_BYCOMMAND|stopActivated);
  645. break;
  646. }
  647. }
  648. VOID
  649. CZippyWindow::OnFindMessageString(
  650. IN LPARAM lParam
  651. )
  652. /*++
  653. Routine Description:
  654. This handles a message from the find/replace
  655. dialog when a user hits a button
  656. Arguments:
  657. lParam - LPFINDREPLACE struct for the dialog
  658. Return value:
  659. None
  660. --*/
  661. {
  662. LPFINDREPLACE lpFindReplace;
  663. lpFindReplace = (LPFINDREPLACE)lParam;
  664. if (lpFindReplace->Flags & FR_DIALOGTERM) {
  665. // the dialog is closing
  666. m_hWndFindReplace = NULL;
  667. } else if (lpFindReplace->Flags & FR_FINDNEXT) {
  668. // the user selected find
  669. DoFindNext(lpFindReplace);
  670. } else if (lpFindReplace->Flags & FR_REPLACE) {
  671. DoReplace(lpFindReplace);
  672. } else if (lpFindReplace->Flags & FR_REPLACEALL) {
  673. DoReplaceAll(lpFindReplace);
  674. }
  675. }
  676. VOID
  677. CZippyWindow::OnClose(
  678. )
  679. /*++
  680. Routine Description:
  681. When we receive a close window request we prompt
  682. the user to sace the trace if they have changed it.
  683. Arguments:
  684. None
  685. Return value:
  686. None
  687. --*/
  688. {
  689. INT result;
  690. TCHAR dlgMessage[MAX_STR_LEN];
  691. TCHAR dlgTitle[MAX_STR_LEN];
  692. if (SendMessage(m_hControlWnd,EM_GETMODIFY,0,0)) {
  693. LoadStringSimple(IDS_SAVEFILEPROMPT,dlgMessage);
  694. LoadStringSimple(IDS_ZIPPYWINDOWTITLE,dlgTitle);
  695. result = MessageBox(m_hWnd,dlgMessage,dlgTitle,MB_YESNOCANCEL|MB_ICONQUESTION);
  696. switch (result) {
  697. case IDYES:
  698. OnSave();
  699. if (SendMessage(m_hControlWnd,EM_GETMODIFY,0,0)) {
  700. // if there was an error saving we will try again.
  701. PostMessage(m_hWnd,WM_CLOSE,0,0);
  702. return;
  703. }
  704. case IDNO:
  705. DestroyWindow(m_hWnd);
  706. break;
  707. }
  708. } else {
  709. DestroyWindow(m_hWnd);
  710. }
  711. }
  712. VOID
  713. CZippyWindow::OnDestroy(
  714. )
  715. /*++
  716. Routine Description:
  717. When the main window exits we halt the message loop
  718. Arguments:
  719. None
  720. Return value:
  721. None
  722. --*/
  723. {
  724. // If we don't clean up the tracing stuff here. There is a long
  725. // delay exiting for some reason.
  726. CTraceManager::_CleanupTraceManager();
  727. PostQuitMessage(0);
  728. }
  729. VOID
  730. CZippyWindow::OnCommand(
  731. IN WPARAM wParam,
  732. IN LPARAM lParam
  733. )
  734. /*++
  735. Routine Description:
  736. Below is WM_COMMAND and all the handler functions.
  737. The individual handler funcitons are not
  738. that interesting so I didn't individually comment them.
  739. Arguments:
  740. wParam - (loword) command the user selected
  741. lParam - not used but it is the control
  742. Return value:
  743. None
  744. --*/
  745. {
  746. WORD command;
  747. command = LOWORD(wParam);
  748. switch (command) {
  749. case ID_FILE_SAVE:
  750. OnSave();
  751. break;
  752. case ID_FILE_SAVEAS:
  753. OnSaveAs();
  754. break;
  755. case ID_FILE_LOADCONF:
  756. OnLoadConfiguration();
  757. break;
  758. case ID_FILE_SAVECONF:
  759. OnSaveConfiguration();
  760. break;
  761. case ID_FILE_SAVECONFAS:
  762. OnSaveConfigurationAs();
  763. break;
  764. case ID_FILE_EXIT:
  765. OnExit();
  766. break;
  767. case ID_EDIT_UNDO:
  768. OnUndo();
  769. break;
  770. case ID_EDIT_REDO:
  771. OnRedo();
  772. break;
  773. case ID_EDIT_CUT:
  774. OnCut();
  775. break;
  776. case ID_EDIT_COPY:
  777. OnCopy();
  778. break;
  779. case ID_EDIT_PASTE:
  780. OnPaste();
  781. break;
  782. case ID_EDIT_FIND:
  783. OnFind();
  784. break;
  785. case ID_EDIT_FINDNEXT:
  786. OnFindNext();
  787. break;
  788. case ID_EDIT_REPLACE:
  789. OnReplace();
  790. break;
  791. case ID_EDIT_SELECTALL:
  792. OnSelectAll();
  793. break;
  794. case ID_VIEW_STATUSBAR:
  795. OnChangeStatusBar();
  796. break;
  797. case ID_MONITORING_START:
  798. OnStartTracing();
  799. break;
  800. case ID_MONITORING_STOP:
  801. OnStopTracing();
  802. break;
  803. case ID_MONITORING_RECORD:
  804. OnRecordTracing();
  805. break;
  806. case ID_MONITORING_CLEARSCREEN:
  807. OnClearScreen();
  808. break;
  809. case ID_MONITORING_RESETTRACEFILES:
  810. OnResetTraceFiles();
  811. break;
  812. case ID_MONITORING_PREFERENCES:
  813. OnPreferences();
  814. break;
  815. case ID_HELP_ABOUTEZIPPY:
  816. OnAbout();
  817. break;
  818. }
  819. }
  820. VOID CZippyWindow::OnSave()
  821. {
  822. if (m_SaveFile[0] == 0) {
  823. // if we don't have a file name do the
  824. // Save As version
  825. OnSaveAs();
  826. } else {
  827. DoSaveInternal();
  828. }
  829. }
  830. VOID CZippyWindow::OnSaveAs()
  831. {
  832. OPENFILENAME fileInfo;
  833. BOOL bResult;
  834. ZeroMemory(&fileInfo,sizeof(fileInfo));
  835. fileInfo.lStructSize = sizeof(fileInfo);
  836. fileInfo.hwndOwner = m_hWnd;
  837. fileInfo.hInstance = g_hInstance;
  838. fileInfo.lpstrFilter = SAVE_FILE_TYPE;
  839. fileInfo.lpstrFile = m_SaveFile;
  840. fileInfo.nMaxFile = MAX_STR_LEN;
  841. fileInfo.Flags = OFN_OVERWRITEPROMPT;
  842. fileInfo.lpstrDefExt = SAVE_FILE_EXTENSION;
  843. bResult = GetSaveFileName(&fileInfo);
  844. if (!bResult) {
  845. return;
  846. }
  847. DoSaveInternal();
  848. }
  849. VOID CZippyWindow::OnLoadConfiguration()
  850. {
  851. OPENFILENAME fileInfo;
  852. BOOL bResult;
  853. ZeroMemory(&fileInfo,sizeof(fileInfo));
  854. fileInfo.lStructSize = sizeof(fileInfo);
  855. fileInfo.hwndOwner = m_hWnd;
  856. fileInfo.hInstance = g_hInstance;
  857. fileInfo.lpstrFilter = SAVE_CONF_FILE_TYPE;
  858. fileInfo.lpstrFile = m_LoadConfFile;
  859. fileInfo.nMaxFile = MAX_STR_LEN;
  860. fileInfo.Flags = OFN_FILEMUSTEXIST;
  861. fileInfo.lpstrDefExt = SAVE_CONF_FILE_EXTENSION;
  862. bResult = GetOpenFileName(&fileInfo);
  863. if (!bResult) {
  864. return;
  865. }
  866. DoLoadConfInternal();
  867. }
  868. VOID CZippyWindow::OnSaveConfiguration()
  869. {
  870. if (m_SaveConfFile[0] == 0) {
  871. // if we don't have a file name do the
  872. // Save As version
  873. OnSaveConfigurationAs();
  874. } else {
  875. DoSaveConfInternal();
  876. }
  877. }
  878. VOID CZippyWindow::OnSaveConfigurationAs()
  879. {
  880. OPENFILENAME fileInfo;
  881. BOOL bResult;
  882. ZeroMemory(&fileInfo,sizeof(fileInfo));
  883. fileInfo.lStructSize = sizeof(fileInfo);
  884. fileInfo.hwndOwner = m_hWnd;
  885. fileInfo.hInstance = g_hInstance;
  886. fileInfo.lpstrFilter = SAVE_CONF_FILE_TYPE;
  887. fileInfo.lpstrFile = m_SaveConfFile;
  888. fileInfo.nMaxFile = MAX_STR_LEN;
  889. fileInfo.Flags = OFN_OVERWRITEPROMPT;
  890. fileInfo.lpstrDefExt = SAVE_CONF_FILE_EXTENSION;
  891. bResult = GetSaveFileName(&fileInfo);
  892. if (!bResult) {
  893. return;
  894. }
  895. DoSaveConfInternal();
  896. }
  897. VOID CZippyWindow::OnExit()
  898. {
  899. PostMessage(m_hWnd,WM_CLOSE,0,0);
  900. }
  901. // All the edit menu commands. Except for select all they just call the
  902. // corresponding message in the rich edit control. Select all has to
  903. // manually set the selection
  904. VOID CZippyWindow::OnUndo()
  905. {
  906. SendMessage(m_hControlWnd,WM_UNDO,0,0);
  907. }
  908. VOID CZippyWindow::OnRedo()
  909. {
  910. SendMessage(m_hControlWnd,EM_REDO,0,0);
  911. }
  912. VOID CZippyWindow::OnCut()
  913. {
  914. SendMessage(m_hControlWnd,WM_CUT,0,0);
  915. }
  916. VOID CZippyWindow::OnCopy()
  917. {
  918. SendMessage(m_hControlWnd,WM_COPY,0,0);
  919. }
  920. VOID CZippyWindow::OnPaste()
  921. {
  922. SendMessage(m_hControlWnd,WM_PASTE,0,0);
  923. }
  924. VOID CZippyWindow::OnSelectAll()
  925. {
  926. CHARRANGE selection;
  927. selection.cpMin = 0;
  928. selection.cpMax = -1;
  929. SendMessage(m_hControlWnd,EM_EXSETSEL,0,(LPARAM)&selection);
  930. }
  931. VOID CZippyWindow::OnFind()
  932. {
  933. CHARRANGE currentSel;
  934. TEXTRANGE textRange;
  935. if (IsWindow(m_hWndFindReplace) && !m_bIsFindNotReplace) {
  936. // If they were in a replace dialog we destroy it and then
  937. // start over with a find dialog
  938. DestroyWindow(m_hWndFindReplace);
  939. m_hWndFindReplace = NULL;
  940. }
  941. if (!IsWindow(m_hWndFindReplace)) {
  942. SendMessage(m_hControlWnd,EM_EXGETSEL,0,(LPARAM)&currentSel);
  943. textRange.chrg.cpMin = currentSel.cpMin;
  944. if (currentSel.cpMax - currentSel.cpMin >= FIND_REPLACE_BUFFER_SIZE) {
  945. textRange.chrg.cpMax = currentSel.cpMin + FIND_REPLACE_BUFFER_SIZE-1;
  946. } else {
  947. textRange.chrg.cpMax = currentSel.cpMax;
  948. }
  949. textRange.lpstrText = m_FindReplace.lpstrFindWhat;
  950. SendMessage(m_hControlWnd,EM_GETTEXTRANGE,0,(LPARAM)&textRange);
  951. m_bIsFindNotReplace = TRUE;
  952. m_FindReplace.hwndOwner = m_hWnd;
  953. m_FindReplace.hInstance = g_hInstance;
  954. m_FindReplace.Flags = FR_DOWN|FR_HIDEUPDOWN;
  955. m_FindReplace.wFindWhatLen = FIND_REPLACE_BUFFER_SIZE;
  956. m_hWndFindReplace = FindText(&m_FindReplace);
  957. } else {
  958. SetActiveWindow(m_hWndFindReplace);
  959. }
  960. }
  961. VOID CZippyWindow::OnFindNext()
  962. {
  963. DoFindNext(&m_FindReplace);
  964. }
  965. VOID CZippyWindow::OnReplace()
  966. {
  967. CHARRANGE currentSel;
  968. TEXTRANGE textRange;
  969. if (IsWindow(m_hWndFindReplace) && m_bIsFindNotReplace) {
  970. // If they were in a replace dialog we destroy it and then
  971. // start over with a find dialog
  972. DestroyWindow(m_hWndFindReplace);
  973. m_hWndFindReplace = NULL;
  974. }
  975. if (!IsWindow(m_hWndFindReplace)) {
  976. SendMessage(m_hControlWnd,EM_EXGETSEL,0,(LPARAM)&currentSel);
  977. textRange.chrg.cpMin = currentSel.cpMin;
  978. if (currentSel.cpMax - currentSel.cpMin >= FIND_REPLACE_BUFFER_SIZE) {
  979. textRange.chrg.cpMax = currentSel.cpMin + FIND_REPLACE_BUFFER_SIZE-1;
  980. } else {
  981. textRange.chrg.cpMax = currentSel.cpMax;
  982. }
  983. textRange.lpstrText = m_FindReplace.lpstrFindWhat;
  984. SendMessage(m_hControlWnd,EM_GETTEXTRANGE,0,(LPARAM)&textRange);
  985. m_bIsFindNotReplace = FALSE;
  986. m_FindReplace.hwndOwner = m_hWnd;
  987. m_FindReplace.hInstance = g_hInstance;
  988. m_FindReplace.Flags = FR_DOWN;
  989. m_FindReplace.wFindWhatLen = FIND_REPLACE_BUFFER_SIZE;
  990. m_FindReplace.wReplaceWithLen = FIND_REPLACE_BUFFER_SIZE;
  991. m_hWndFindReplace = ReplaceText(&m_FindReplace);
  992. } else {
  993. SetActiveWindow(m_hWndFindReplace);
  994. }
  995. }
  996. VOID CZippyWindow::OnChangeStatusBar()
  997. {
  998. RECT clientRect;
  999. if (IsWindowVisible(m_hStatusWnd)) {
  1000. ShowWindow(m_hStatusWnd,SW_HIDE);
  1001. } else {
  1002. ShowWindow(m_hStatusWnd,SW_SHOW);
  1003. }
  1004. // we do this to make the client windows resize themselves
  1005. // around the status bar
  1006. GetClientRect(m_hWnd,&clientRect);
  1007. OnSize(clientRect.right,clientRect.bottom);
  1008. }
  1009. VOID CZippyWindow::OnStartTracing()
  1010. {
  1011. m_bIsTracing = TRUE;
  1012. }
  1013. VOID CZippyWindow::OnStopTracing()
  1014. {
  1015. m_bIsTracing = FALSE;
  1016. }
  1017. VOID CZippyWindow::OnRecordTracing()
  1018. {
  1019. CModalOkDialog recordDialog;
  1020. LPSAVEDOUTPUT lpTemp;
  1021. m_bIsStoringTraceData = TRUE;
  1022. recordDialog.DoModal(MAKEINTRESOURCE(IDD_RECORDTRACE),m_hWnd);
  1023. WaitForSingleObject(m_hAppendMutex,INFINITE);
  1024. m_bIsStoringTraceData = FALSE;
  1025. while (m_lpSavedOutputStart) {
  1026. AppendTextToWindow(m_lpSavedOutputStart->procID,
  1027. m_lpSavedOutputStart->text,m_lpSavedOutputStart->len);
  1028. lpTemp = m_lpSavedOutputStart;
  1029. m_lpSavedOutputStart = m_lpSavedOutputStart->next;
  1030. HeapFree(GetProcessHeap(),0,lpTemp);
  1031. }
  1032. m_lpSavedOutputTail = NULL;
  1033. ReleaseMutex(m_hAppendMutex);
  1034. }
  1035. VOID CZippyWindow::OnClearScreen()
  1036. {
  1037. TCHAR dlgTitle[MAX_STR_LEN];
  1038. TCHAR dlgMessage[MAX_STR_LEN];
  1039. LoadStringSimple(IDS_CLEARCONFIRMTITLE,dlgTitle);
  1040. LoadStringSimple(IDS_CLEARCONFIRMMESSAGE,dlgMessage);
  1041. if (IDYES != MessageBox(m_hWnd,dlgMessage,dlgTitle,MB_YESNO)) {
  1042. return;
  1043. }
  1044. OnSelectAll();
  1045. SendMessage(m_hControlWnd, EM_REPLACESEL,FALSE,(LPARAM)_T(""));
  1046. }
  1047. VOID CZippyWindow::OnResetTraceFiles()
  1048. {
  1049. TCHAR dlgTitle[MAX_STR_LEN];
  1050. TCHAR dlgMessage[MAX_STR_LEN];
  1051. LoadStringSimple(IDS_CONFIRMRESETTRACETITLE,dlgTitle);
  1052. LoadStringSimple(IDS_CONFIRMRESETTRACEMESSAGE,dlgMessage);
  1053. if (IDYES != MessageBox(m_hWnd,dlgMessage,dlgTitle,MB_YESNO)) {
  1054. return;
  1055. }
  1056. m_rTracer->TRC_ResetTraceFiles();
  1057. }
  1058. VOID CZippyWindow::OnPreferences()
  1059. {
  1060. COptionsDialog optionsDialog(m_rTracer);
  1061. optionsDialog.DoDialog(m_hWnd);
  1062. }
  1063. VOID CZippyWindow::OnAbout()
  1064. {
  1065. HICON appIcon;
  1066. TCHAR appTitle[MAX_STR_LEN];
  1067. TCHAR appOtherStuff[MAX_STR_LEN];
  1068. LoadStringSimple(IDS_ABOUTAPPTITLE,appTitle);
  1069. LoadStringSimple(IDS_ABOUTOTHERSTUFF,appOtherStuff);
  1070. appIcon = (HICON)LoadImage(g_hInstance,MAKEINTRESOURCE(IDI_MAINFRAME),
  1071. IMAGE_ICON,0,0,LR_SHARED);
  1072. if( NULL != appIcon )
  1073. {
  1074. ShellAbout(m_hWnd,appTitle,appOtherStuff,appIcon);
  1075. // even though the icon is shared we should destroy it to keep the reference
  1076. // count somewhat sane.
  1077. DestroyIcon(appIcon);
  1078. }
  1079. }
  1080. //
  1081. // *** Private Helper Functions ***
  1082. //
  1083. //
  1084. // Computes the color for the given debut output. It parses the text to dtermine
  1085. // what the thread id is and then either retrieves the color for that thread or
  1086. // picks a new color
  1087. //
  1088. BOOL CZippyWindow::ComputeNewColor(DWORD processID, LPCTSTR text, UINT len, CHARFORMAT *lpFormat)
  1089. {
  1090. LPTSTR procIdStr;
  1091. DWORD threadId;
  1092. LPCTSTR procBase;
  1093. UINT maxStrLen;
  1094. BOOL bSuccess;
  1095. UINT threadLen;
  1096. LPTHREADCOLOR newColor;
  1097. procIdStr = NULL;
  1098. bSuccess = TRUE;
  1099. // first we will just make sure the format struct is in a safe state.
  1100. lpFormat->cbSize = sizeof(CHARFORMAT);
  1101. lpFormat->dwMask = 0;
  1102. maxStrLen = sizeof(DWORD) * 2;
  1103. procIdStr = (LPTSTR)HeapAlloc(GetProcessHeap(),0,sizeof(TCHAR) * (maxStrLen+1));
  1104. if (!procIdStr) {
  1105. bSuccess = FALSE;
  1106. goto CLEANUP_AND_EXIT;
  1107. }
  1108. wsprintf(procIdStr,TRC_PROC_FMT,processID);
  1109. procBase = _tcsstr(text,procIdStr);
  1110. if (!procBase) {
  1111. bSuccess = FALSE;
  1112. goto CLEANUP_AND_EXIT;
  1113. }
  1114. procBase += _tcslen(procIdStr);
  1115. if (*procBase != ':') {
  1116. bSuccess = FALSE;
  1117. goto CLEANUP_AND_EXIT;
  1118. }
  1119. procBase++;
  1120. threadLen = 0;
  1121. while (_istxdigit(*(procBase + threadLen))) {
  1122. threadLen++;
  1123. }
  1124. if (!threadLen) {
  1125. bSuccess = FALSE;
  1126. goto CLEANUP_AND_EXIT;
  1127. }
  1128. threadId = ConvertHexStrToDword(procBase,threadLen);
  1129. newColor = FindColorForThread(processID,threadId);
  1130. lpFormat->crTextColor = newColor->color;
  1131. lpFormat->dwEffects = 0;
  1132. lpFormat->dwMask = CFM_COLOR;
  1133. CLEANUP_AND_EXIT:
  1134. if (procIdStr) {
  1135. HeapFree(GetProcessHeap(),0,procIdStr);
  1136. }
  1137. return bSuccess;
  1138. }
  1139. //
  1140. // This converts a hex string to the equivalent DWORD value for example
  1141. // the string "FF" would cause the function to return 0xFF (255)
  1142. //
  1143. DWORD CZippyWindow::ConvertHexStrToDword(LPCTSTR str, UINT strLen)
  1144. {
  1145. DWORD total;
  1146. TCHAR current;
  1147. INT currentValue;
  1148. total = 0;
  1149. if (strLen == 0) {
  1150. strLen = _tcslen(str);
  1151. }
  1152. while (strLen-- > 0) {
  1153. current = *(str++);
  1154. if (_istdigit(current)) {
  1155. currentValue = current - '0';
  1156. } else {
  1157. current = (TCHAR)tolower((INT)current);
  1158. currentValue = 10 + (current - 'a');
  1159. }
  1160. total = (total * 16) + currentValue;
  1161. }
  1162. return total;
  1163. }
  1164. // This looks up the color for the given thread. If the thread has not been
  1165. // seen before a new color is picked and the color for the thread is saved.
  1166. LPTHREADCOLOR CZippyWindow::FindColorForThread(DWORD processId, DWORD threadId)
  1167. {
  1168. int i = 0;
  1169. LPTHREADCOLOR lpThreadColor;
  1170. for (i=0;i<COLOR_HISTORY_COUNT;i++) {
  1171. if (m_threadHistory[i].threadId == threadId &&
  1172. m_threadHistory[i].processId == processId) {
  1173. return &m_threadHistory[i];
  1174. }
  1175. }
  1176. // else this is the first time we saw the thread
  1177. lpThreadColor = &m_threadHistory[m_nextThreadIndex++];
  1178. if (m_nextThreadIndex == COLOR_HISTORY_COUNT) {
  1179. m_nextThreadIndex = 0;
  1180. }
  1181. lpThreadColor->processId = processId;
  1182. lpThreadColor->threadId = threadId;
  1183. lpThreadColor->color = colors[m_nextThreadColor++];
  1184. if (m_nextThreadColor == NUM_COLORS) {
  1185. m_nextThreadColor = 0;
  1186. }
  1187. return lpThreadColor;
  1188. }
  1189. // This handles actually saving the document.
  1190. VOID CZippyWindow::DoSaveInternal()
  1191. {
  1192. HANDLE saveFile;
  1193. EDITSTREAM saveStream;
  1194. LRESULT bytesSaved;
  1195. TCHAR dlgTitle[MAX_STR_LEN];
  1196. TCHAR dlgMessage[MAX_STR_LEN];
  1197. saveFile = CreateFile(m_SaveFile,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
  1198. 0,NULL);
  1199. if (saveFile==INVALID_HANDLE_VALUE) {
  1200. LoadStringSimple(IDS_FILEOPENERROR,dlgMessage);
  1201. LoadStringSimple(IDS_ZIPPYWINDOWTITLE,dlgTitle);
  1202. MessageBox(m_hWnd,dlgMessage,dlgTitle,MB_OK|MB_ICONERROR);
  1203. return;
  1204. }
  1205. saveStream.dwCookie = (DWORD_PTR)saveFile;
  1206. saveStream.dwError = 0;
  1207. saveStream.pfnCallback = SaveCallback;
  1208. bytesSaved = SendMessage(m_hControlWnd,EM_STREAMOUT,SF_TEXT,(LPARAM)&saveStream);
  1209. CloseHandle(saveFile);
  1210. if (saveStream.dwError != 0) {
  1211. LoadStringSimple(IDS_FILESAVEERROR,dlgMessage);
  1212. LoadStringSimple(IDS_ZIPPYWINDOWTITLE,dlgTitle);
  1213. MessageBox(m_hWnd,dlgMessage,dlgTitle,MB_OK|MB_ICONERROR);
  1214. } else {
  1215. SendMessage(m_hControlWnd,EM_SETMODIFY,FALSE,0);
  1216. }
  1217. }
  1218. // This is a private callback function which rich edit calls when
  1219. // saving out the document
  1220. static DWORD CALLBACK
  1221. SaveCallback(DWORD_PTR dwCookie,LPBYTE pbBuff,LONG cb,LONG *pcb)
  1222. {
  1223. HANDLE fileHandle;
  1224. fileHandle = (HANDLE)dwCookie;
  1225. if (!WriteFile(fileHandle,pbBuff,cb,(PULONG)pcb,NULL)) {
  1226. return GetLastError();
  1227. }
  1228. return 0;
  1229. }
  1230. // As the function name says this does a find next operation
  1231. // on the rich edit control
  1232. BOOL CZippyWindow::DoFindNext(LPFINDREPLACE lpFindReplace)
  1233. {
  1234. FINDTEXTEX findText;
  1235. WPARAM searchOptions;
  1236. CHARRANGE currentSel;
  1237. TCHAR dlgTitle[MAX_STR_LEN];
  1238. TCHAR dlgMessage[MAX_STR_LEN];
  1239. SendMessage(m_hControlWnd,EM_EXGETSEL,0,(LPARAM)&currentSel);
  1240. findText.chrg.cpMin = currentSel.cpMax;
  1241. findText.chrg.cpMax = -1;
  1242. findText.lpstrText = lpFindReplace->lpstrFindWhat;
  1243. searchOptions = FR_DOWN;
  1244. if (lpFindReplace->Flags & FR_MATCHCASE) {
  1245. searchOptions |= FR_MATCHCASE;
  1246. }
  1247. if (lpFindReplace->Flags & FR_WHOLEWORD) {
  1248. searchOptions |= FR_WHOLEWORD;
  1249. }
  1250. if (0 <= SendMessage(m_hControlWnd, EM_FINDTEXTEX,searchOptions,
  1251. (LPARAM)&findText)) {
  1252. SendMessage(m_hControlWnd, EM_EXSETSEL,0,(LPARAM)&findText.chrgText);
  1253. } else {
  1254. LoadStringSimple(IDS_SEARCHFAILURE,dlgMessage);
  1255. LoadStringSimple(IDS_ZIPPYWINDOWTITLE,dlgTitle);
  1256. MessageBox(m_hWndFindReplace,dlgMessage,dlgTitle,MB_OK);
  1257. return FALSE;
  1258. }
  1259. return TRUE;
  1260. }
  1261. // This does a replace operation on the control
  1262. BOOL CZippyWindow::DoReplace(LPFINDREPLACE lpFindReplace)
  1263. {
  1264. FINDTEXTEX findText;
  1265. WPARAM searchOptions;
  1266. CHARRANGE currentSel;
  1267. TCHAR dlgTitle[MAX_STR_LEN];
  1268. TCHAR dlgMessage[MAX_STR_LEN];
  1269. SendMessage(m_hControlWnd,EM_EXGETSEL,0,(LPARAM)&currentSel);
  1270. findText.chrg.cpMin = currentSel.cpMin;
  1271. findText.chrg.cpMax = -1;
  1272. findText.lpstrText = lpFindReplace->lpstrFindWhat;
  1273. searchOptions = FR_DOWN;
  1274. if (lpFindReplace->Flags & FR_MATCHCASE) {
  1275. searchOptions |= FR_MATCHCASE;
  1276. }
  1277. if (lpFindReplace->Flags & FR_WHOLEWORD) {
  1278. searchOptions |= FR_WHOLEWORD;
  1279. }
  1280. if (-1 == SendMessage(m_hControlWnd, EM_FINDTEXTEX,searchOptions,
  1281. (LPARAM)&findText)) {
  1282. // if we can't find what they were looking for just give up.
  1283. LoadStringSimple(IDS_SEARCHFAILURE,dlgMessage);
  1284. LoadStringSimple(IDS_ZIPPYWINDOWTITLE,dlgTitle);
  1285. MessageBox(m_hWndFindReplace,dlgMessage,dlgTitle,MB_OK);
  1286. return FALSE;
  1287. }
  1288. if (currentSel.cpMin == findText.chrgText.cpMin &&
  1289. currentSel.cpMax == findText.chrgText.cpMax) {
  1290. SendMessage(m_hControlWnd,EM_REPLACESEL,0,(LPARAM)lpFindReplace->lpstrReplaceWith);
  1291. // Now select the next occurrence
  1292. return DoFindNext(lpFindReplace);
  1293. } else {
  1294. // They weren't on what they were searching for so select it.
  1295. SendMessage(m_hControlWnd, EM_EXSETSEL,0,(LPARAM)&findText.chrgText);
  1296. }
  1297. return TRUE;
  1298. }
  1299. // This loops on DoReplace until DoReplace returns FALSE
  1300. VOID CZippyWindow::DoReplaceAll(LPFINDREPLACE lpFindReplace)
  1301. {
  1302. while (DoReplace(lpFindReplace));
  1303. }
  1304. // This actually saves the traceconfiguration. We just write
  1305. // out the binary config structure to the file
  1306. VOID CZippyWindow::DoSaveConfInternal()
  1307. {
  1308. HANDLE saveFile;
  1309. TRC_CONFIG trcConfig;
  1310. TCHAR dlgTitle[MAX_STR_LEN];
  1311. TCHAR dlgMessage[MAX_STR_LEN];
  1312. DWORD bytesWritten;
  1313. saveFile = CreateFile(m_SaveConfFile,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
  1314. 0,NULL);
  1315. if (saveFile==INVALID_HANDLE_VALUE) {
  1316. LoadStringSimple(IDS_FILEOPENERROR,dlgMessage);
  1317. LoadStringSimple(IDS_ZIPPYWINDOWTITLE,dlgTitle);
  1318. MessageBox(m_hWnd,dlgMessage,dlgTitle,MB_OK|MB_ICONERROR);
  1319. return;
  1320. }
  1321. m_rTracer->GetCurrentConfig(&trcConfig);
  1322. if (!WriteFile(saveFile,&trcConfig,sizeof(trcConfig),&bytesWritten,NULL) ||
  1323. bytesWritten != sizeof(trcConfig)) {
  1324. LoadStringSimple(IDS_FILESAVEERROR,dlgMessage);
  1325. LoadStringSimple(IDS_ZIPPYWINDOWTITLE,dlgTitle);
  1326. MessageBox(m_hWnd,dlgMessage,dlgTitle,MB_OK|MB_ICONERROR);
  1327. }
  1328. CloseHandle(saveFile);
  1329. }
  1330. // This reads in the binary configuration structure and then
  1331. // sets it as the current tracing config
  1332. VOID CZippyWindow::DoLoadConfInternal()
  1333. {
  1334. HANDLE openFile;
  1335. DWORD bytesRead;
  1336. TRC_CONFIG trcConfig;
  1337. TCHAR dlgTitle[MAX_STR_LEN];
  1338. TCHAR dlgMessage[MAX_STR_LEN];
  1339. openFile = CreateFile(m_LoadConfFile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
  1340. 0,NULL);
  1341. if (openFile==INVALID_HANDLE_VALUE) {
  1342. LoadStringSimple(IDS_FILELOADOPENERROR,dlgMessage);
  1343. LoadStringSimple(IDS_ZIPPYWINDOWTITLE,dlgTitle);
  1344. MessageBox(m_hWnd,dlgMessage,dlgTitle,MB_OK|MB_ICONERROR);
  1345. return;
  1346. }
  1347. if (!ReadFile(openFile,&trcConfig,sizeof(trcConfig),&bytesRead,NULL)||
  1348. bytesRead != sizeof(trcConfig)) {
  1349. LoadStringSimple(IDS_FILELOADERROR,dlgMessage);
  1350. LoadStringSimple(IDS_ZIPPYWINDOWTITLE,dlgTitle);
  1351. MessageBox(m_hWnd,dlgMessage,dlgTitle,MB_OK|MB_ICONERROR);
  1352. }
  1353. m_rTracer->SetCurrentConfig(&trcConfig);
  1354. }
  1355. // Reads the saved window position in from the registry.
  1356. VOID CZippyWindow::GetSavedWindowPos(LPRECT savedPos)
  1357. {
  1358. DWORD dwResult;
  1359. DWORD dwSize;
  1360. DWORD dwType;
  1361. RECT rect;
  1362. HKEY hKey;
  1363. savedPos->top = WINDOW_DEF_TOP;
  1364. savedPos->bottom = WINDOW_DEF_BOTTOM;
  1365. savedPos->left = WINDOW_DEF_LEFT;
  1366. savedPos->right = WINDOW_DEF_RIGHT;
  1367. dwResult = RegOpenKeyEx(HKEY_CURRENT_USER,ZIPPY_REG_KEY,0,
  1368. KEY_QUERY_VALUE,&hKey);
  1369. if (dwResult) {
  1370. return;
  1371. }
  1372. dwSize = sizeof(RECT);
  1373. dwResult = RegQueryValueEx(hKey,ZIPPY_WINDOW_POS_VALUE,NULL,&dwType,
  1374. (LPBYTE)&rect,&dwSize);
  1375. RegCloseKey(hKey);
  1376. if (dwResult||dwSize != sizeof(RECT)||dwType!=REG_BINARY) {
  1377. return;
  1378. }
  1379. *savedPos = rect;
  1380. }
  1381. // Saves the window position out to the registry
  1382. VOID CZippyWindow::SaveWindowPos(LPRECT newPos)
  1383. {
  1384. DWORD dwResult;
  1385. HKEY hKey;
  1386. dwResult = RegCreateKeyEx(HKEY_CURRENT_USER,ZIPPY_REG_KEY,0,_T(""),0,
  1387. KEY_SET_VALUE,NULL,&hKey,NULL);
  1388. if (dwResult) {
  1389. return;
  1390. }
  1391. RegSetValueEx(hKey,ZIPPY_WINDOW_POS_VALUE,0,REG_BINARY,
  1392. (LPBYTE)newPos,sizeof(RECT));
  1393. RegCloseKey(hKey);
  1394. }