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.

660 lines
15 KiB

  1. /*++
  2. Copyright (c) 1992-2000 Microsoft Corporation
  3. Module Name:
  4. Menu.c
  5. Abstract:
  6. This module contains the support for Windbg's menu.
  7. --*/
  8. #include "precomp.hxx"
  9. #pragma hdrstop
  10. MRU_ENTRY* g_MruFiles[MAX_MRU_FILES];
  11. HMENU g_MruMenu;
  12. //
  13. // EnableMenuItemTable contains the menu IDs for all menu items whose
  14. // enabled state needs to be determined dynamically i.e. based on the state
  15. // of Windbg.
  16. //
  17. UINT
  18. g_EnableMenuItemTable[ ] =
  19. {
  20. IDM_FILE_CLOSE,
  21. IDM_FILE_OPEN_EXECUTABLE,
  22. IDM_FILE_ATTACH,
  23. IDM_FILE_OPEN_CRASH_DUMP,
  24. IDM_FILE_CONNECT_TO_REMOTE,
  25. IDM_FILE_KERNEL_DEBUG,
  26. IDM_FILE_SAVE_WORKSPACE,
  27. IDM_FILE_SAVE_WORKSPACE_AS,
  28. IDM_FILE_CLEAR_WORKSPACE,
  29. IDM_EDIT_CUT,
  30. IDM_EDIT_COPY,
  31. IDM_EDIT_PASTE,
  32. IDM_EDIT_SELECT_ALL,
  33. IDM_EDIT_ADD_TO_COMMAND_HISTORY,
  34. IDM_EDIT_CLEAR_COMMAND_HISTORY,
  35. IDM_EDIT_FIND,
  36. IDM_EDIT_GOTO_ADDRESS,
  37. IDM_EDIT_GOTO_LINE,
  38. IDM_EDIT_BREAKPOINTS,
  39. IDM_EDIT_PROPERTIES,
  40. IDM_VIEW_TOGGLE_VERBOSE,
  41. IDM_VIEW_SHOW_VERSION,
  42. IDM_DEBUG_GO,
  43. IDM_DEBUG_GO_UNHANDLED,
  44. IDM_DEBUG_GO_HANDLED,
  45. IDM_DEBUG_RESTART,
  46. IDM_DEBUG_STOPDEBUGGING,
  47. IDM_DEBUG_BREAK,
  48. IDM_DEBUG_STEPINTO,
  49. IDM_DEBUG_STEPOVER,
  50. IDM_DEBUG_STEPOUT,
  51. IDM_DEBUG_RUNTOCURSOR,
  52. IDM_DEBUG_SOURCE_MODE,
  53. IDM_DEBUG_SOURCE_MODE_ON,
  54. IDM_DEBUG_SOURCE_MODE_OFF,
  55. IDM_DEBUG_EVENT_FILTERS,
  56. IDM_DEBUG_MODULES,
  57. IDM_KDEBUG_TOGGLE_BAUDRATE,
  58. IDM_KDEBUG_TOGGLE_INITBREAK,
  59. IDM_KDEBUG_RECONNECT,
  60. IDM_WINDOW_CASCADE,
  61. IDM_WINDOW_TILE_HORZ,
  62. IDM_WINDOW_TILE_VERT,
  63. IDM_WINDOW_ARRANGE,
  64. IDM_WINDOW_ARRANGE_ICONS,
  65. IDM_WINDOW_AUTO_ARRANGE,
  66. IDM_WINDOW_ARRANGE_ALL,
  67. IDM_WINDOW_OVERLAY_SOURCE,
  68. IDM_WINDOW_AUTO_DISASM,
  69. };
  70. #define ELEMENTS_IN_ENABLE_MENU_ITEM_TABLE \
  71. ( sizeof( g_EnableMenuItemTable ) / sizeof( g_EnableMenuItemTable[ 0 ] ))
  72. UINT
  73. CommandIdEnabled(
  74. IN UINT uMenuID
  75. )
  76. /*++
  77. Routine Description:
  78. Determines if a menu item is enabled/disabled based on the current
  79. state of the debugger.
  80. Arguments:
  81. uMenuID - Supplies a menu id whose state is to be determined.
  82. Return Value:
  83. UINT - Returns ( MF_ENABLED | MF_BYCOMMAND ) if the supplied menu ID
  84. is enabled, ( MF_GRAYED | MF_BYCOMMAND) otherwise.
  85. --*/
  86. {
  87. BOOL fEnabled;
  88. HWND hwndChild = MDIGetActive(g_hwndMDIClient, NULL);
  89. PCOMMONWIN_DATA pCommonWinData;
  90. WIN_TYPES nDocType;
  91. nDocType = MINVAL_WINDOW;
  92. pCommonWinData = NULL;
  93. if (hwndChild != NULL)
  94. {
  95. pCommonWinData = GetCommonWinData(hwndChild);
  96. if (pCommonWinData != NULL)
  97. {
  98. nDocType = pCommonWinData->m_enumType;
  99. }
  100. }
  101. //
  102. // Assume menu item is not enabled.
  103. //
  104. fEnabled = FALSE;
  105. switch( uMenuID )
  106. {
  107. case IDM_FILE_SAVE_WORKSPACE:
  108. case IDM_FILE_SAVE_WORKSPACE_AS:
  109. case IDM_FILE_CLEAR_WORKSPACE:
  110. fEnabled = g_Workspace != NULL;
  111. break;
  112. case IDM_DEBUG_SOURCE_MODE:
  113. case IDM_DEBUG_SOURCE_MODE_ON:
  114. case IDM_DEBUG_SOURCE_MODE_OFF:
  115. fEnabled = TRUE;
  116. CheckMenuItem(g_hmenuMain,
  117. IDM_DEBUG_SOURCE_MODE,
  118. GetSrcMode_StatusBar() ? MF_CHECKED : MF_UNCHECKED
  119. );
  120. break;
  121. case IDM_FILE_CLOSE:
  122. fEnabled = (NULL != hwndChild);
  123. break;
  124. case IDM_FILE_OPEN_EXECUTABLE:
  125. case IDM_FILE_ATTACH:
  126. case IDM_FILE_OPEN_CRASH_DUMP:
  127. case IDM_FILE_CONNECT_TO_REMOTE:
  128. case IDM_FILE_KERNEL_DEBUG:
  129. fEnabled = g_TargetClass == DEBUG_CLASS_UNINITIALIZED &&
  130. !g_RemoteClient;
  131. break;
  132. case IDM_EDIT_CUT:
  133. if ( pCommonWinData )
  134. {
  135. fEnabled = pCommonWinData->CanCut();
  136. }
  137. else
  138. {
  139. fEnabled = FALSE;
  140. }
  141. break;
  142. case IDM_EDIT_COPY:
  143. if ( pCommonWinData )
  144. {
  145. fEnabled = pCommonWinData->CanCopy();
  146. }
  147. else
  148. {
  149. fEnabled = FALSE;
  150. }
  151. break;
  152. case IDM_EDIT_PASTE:
  153. //
  154. // If the window is normal, is not read only and is a document
  155. // or cmdwin, determine if the clipboard contains pastable data
  156. // (i.e. clipboard format CF_TEXT).
  157. //
  158. if ( !(pCommonWinData && pCommonWinData->CanPaste()) )
  159. {
  160. fEnabled = FALSE;
  161. }
  162. else
  163. {
  164. fEnabled = FALSE;
  165. if (OpenClipboard(g_hwndFrame))
  166. {
  167. UINT uFormat = 0;
  168. while ( uFormat = EnumClipboardFormats( uFormat ))
  169. {
  170. if ( uFormat == CF_TEXT )
  171. {
  172. fEnabled = TRUE;
  173. break;
  174. }
  175. }
  176. CloseClipboard();
  177. }
  178. }
  179. break;
  180. case IDM_EDIT_SELECT_ALL:
  181. if ( pCommonWinData )
  182. {
  183. fEnabled = pCommonWinData->CanSelectAll();
  184. }
  185. else
  186. {
  187. fEnabled = FALSE;
  188. }
  189. break;
  190. case IDM_EDIT_ADD_TO_COMMAND_HISTORY:
  191. case IDM_EDIT_CLEAR_COMMAND_HISTORY:
  192. fEnabled = GetCmdHwnd() != NULL;
  193. break;
  194. case IDM_EDIT_GOTO_LINE:
  195. fEnabled = pCommonWinData != NULL && pCommonWinData->CanGotoLine();
  196. break;
  197. case IDM_EDIT_FIND:
  198. fEnabled = hwndChild != NULL;
  199. break;
  200. case IDM_EDIT_GOTO_ADDRESS:
  201. fEnabled = g_TargetClass != DEBUG_CLASS_UNINITIALIZED;
  202. break;
  203. case IDM_EDIT_BREAKPOINTS:
  204. fEnabled = IS_TARGET_HALTED();
  205. break;
  206. case IDM_EDIT_PROPERTIES:
  207. if (pCommonWinData)
  208. {
  209. fEnabled = pCommonWinData->HasEditableProperties();
  210. }
  211. else
  212. {
  213. fEnabled = FALSE;
  214. }
  215. break;
  216. case IDM_VIEW_TOGGLE_VERBOSE:
  217. case IDM_VIEW_SHOW_VERSION:
  218. fEnabled = g_TargetClass != DEBUG_CLASS_UNINITIALIZED;
  219. break;
  220. case IDM_DEBUG_GO:
  221. case IDM_DEBUG_GO_HANDLED:
  222. case IDM_DEBUG_GO_UNHANDLED:
  223. fEnabled = IS_TARGET_HALTED();
  224. break;
  225. case IDM_DEBUG_RESTART:
  226. // If no debuggee is running we can only restart if
  227. // enough information was given on the command line.
  228. // If a debuggee is running we can only restart
  229. // created user-mode processes.
  230. fEnabled =
  231. (g_TargetClass == DEBUG_CLASS_UNINITIALIZED &&
  232. g_CommandLineStart == 1) ||
  233. (g_DebugCommandLine != NULL &&
  234. g_TargetClass == DEBUG_CLASS_USER_WINDOWS &&
  235. !g_RemoteClient &&
  236. IS_TARGET_HALTED());
  237. break;
  238. case IDM_DEBUG_STOPDEBUGGING:
  239. // Technically we can support stopping while the
  240. // debuggee is running, but that will generally
  241. // require terminating the engine thread as it
  242. // will most likely be busy and not able to
  243. // quickly exit to stop. If we terminate the
  244. // engine thread at a random point it may
  245. // leave the engine in an unstable or locked state,
  246. // so restrict restarts to situations where
  247. // the engine thread should be available.
  248. fEnabled = g_RemoteClient || IS_TARGET_HALTED();
  249. break;
  250. case IDM_DEBUG_BREAK:
  251. fEnabled = g_TargetClass != DEBUG_CLASS_UNINITIALIZED;
  252. break;
  253. case IDM_DEBUG_STEPINTO:
  254. case IDM_DEBUG_STEPOVER:
  255. case IDM_DEBUG_STEPOUT:
  256. fEnabled = IS_TARGET_HALTED();
  257. break;
  258. case IDM_DEBUG_RUNTOCURSOR:
  259. //
  260. // If the document can return a code address for
  261. // its cursor it is a candidate for run-to-cursor.
  262. //
  263. fEnabled = FALSE;
  264. if (IS_TARGET_HALTED() && pCommonWinData)
  265. {
  266. fEnabled = pCommonWinData->CodeExprAtCaret(NULL, NULL);
  267. }
  268. break;
  269. case IDM_DEBUG_EVENT_FILTERS:
  270. case IDM_DEBUG_MODULES:
  271. fEnabled = IS_TARGET_HALTED();
  272. break;
  273. case IDM_KDEBUG_TOGGLE_BAUDRATE:
  274. case IDM_KDEBUG_TOGGLE_INITBREAK:
  275. case IDM_KDEBUG_RECONNECT:
  276. fEnabled = g_TargetClass == DEBUG_CLASS_KERNEL &&
  277. g_TargetClassQual == DEBUG_KERNEL_CONNECTION;
  278. break;
  279. case IDM_WINDOW_CASCADE:
  280. case IDM_WINDOW_TILE_HORZ:
  281. case IDM_WINDOW_TILE_VERT:
  282. case IDM_WINDOW_ARRANGE:
  283. case IDM_WINDOW_ARRANGE_ICONS:
  284. fEnabled = hwndChild != NULL;
  285. break;
  286. case IDM_WINDOW_AUTO_ARRANGE:
  287. CheckMenuItem(g_hmenuMain,
  288. IDM_WINDOW_AUTO_ARRANGE,
  289. g_WinOptions & WOPT_AUTO_ARRANGE ? MF_CHECKED : MF_UNCHECKED
  290. );
  291. fEnabled = TRUE;
  292. break;
  293. case IDM_WINDOW_ARRANGE_ALL:
  294. CheckMenuItem(g_hmenuMain,
  295. IDM_WINDOW_ARRANGE_ALL,
  296. g_WinOptions & WOPT_ARRANGE_ALL ? MF_CHECKED : MF_UNCHECKED
  297. );
  298. fEnabled = TRUE;
  299. break;
  300. case IDM_WINDOW_OVERLAY_SOURCE:
  301. CheckMenuItem(g_hmenuMain,
  302. IDM_WINDOW_OVERLAY_SOURCE,
  303. g_WinOptions & WOPT_OVERLAY_SOURCE ? MF_CHECKED : MF_UNCHECKED
  304. );
  305. fEnabled = TRUE;
  306. break;
  307. case IDM_WINDOW_AUTO_DISASM:
  308. CheckMenuItem(g_hmenuMain,
  309. IDM_WINDOW_AUTO_DISASM,
  310. g_WinOptions & WOPT_AUTO_DISASM ? MF_CHECKED : MF_UNCHECKED
  311. );
  312. fEnabled = TRUE;
  313. break;
  314. case IDM_FILE_OPEN:
  315. case IDM_VIEW_COMMAND:
  316. case IDM_VIEW_WATCH:
  317. case IDM_VIEW_CALLSTACK:
  318. case IDM_VIEW_MEMORY:
  319. case IDM_VIEW_LOCALS:
  320. case IDM_VIEW_REGISTERS:
  321. case IDM_VIEW_DISASM:
  322. case IDM_VIEW_SCRATCH:
  323. case IDM_VIEW_TOOLBAR:
  324. case IDM_VIEW_STATUS:
  325. case IDM_VIEW_FONT:
  326. case IDM_VIEW_OPTIONS:
  327. case IDM_EDIT_TOGGLEBREAKPOINT:
  328. case IDM_EDIT_LOG_FILE:
  329. // These items are not dynamically enabled
  330. // but are present in the toolbar. The toolbar
  331. // code requests enable state for every item on it
  332. // so these entries need to be present to return TRUE.
  333. fEnabled = TRUE;
  334. break;
  335. default:
  336. DebugPrint("CommandIdEnabled: Unhandled %d (%X)\n",
  337. uMenuID, uMenuID - MENU_SIGNATURE);
  338. // We should have handled everything.
  339. Assert(0);
  340. break;
  341. }
  342. ToolbarIdEnabled(uMenuID, fEnabled);
  343. return (( fEnabled ) ? MF_ENABLED : MF_GRAYED ) | MF_BYCOMMAND;
  344. }
  345. VOID
  346. InitializeMenu(
  347. IN HMENU hMenu
  348. )
  349. /*++
  350. Routine Description:
  351. InitializeMenu sets the enabled/disabled state of all menu items whose
  352. state musr be determined dynamically.
  353. Arguments:
  354. hMenu - Supplies a handle to the menu bar.
  355. Return Value:
  356. None.
  357. --*/
  358. {
  359. INT i;
  360. Dbg(hMenu);
  361. //
  362. // Iterate thrrough the table, enabling/disabling menu items
  363. // as appropriate.
  364. //
  365. for ( i = 0; i < ELEMENTS_IN_ENABLE_MENU_ITEM_TABLE; i++ )
  366. {
  367. EnableMenuItem(hMenu,
  368. g_EnableMenuItemTable[ i ],
  369. CommandIdEnabled( g_EnableMenuItemTable[ i ])
  370. );
  371. }
  372. }
  373. ULONG
  374. MruEntrySize(PTSTR File)
  375. {
  376. ULONG Len = strlen(File) + 1;
  377. return sizeof(MRU_ENTRY) + (Len & ~3);
  378. }
  379. void
  380. ClearMruMenu(void)
  381. {
  382. while (GetMenuItemCount(g_MruMenu) > 0)
  383. {
  384. if (!DeleteMenu(g_MruMenu, 0, MF_BYPOSITION))
  385. {
  386. break;
  387. }
  388. }
  389. }
  390. VOID
  391. AddFileToMru(ULONG FileUse, PTSTR File)
  392. {
  393. ULONG Len = MruEntrySize(File);
  394. MRU_ENTRY* Entry = (MRU_ENTRY*)malloc(Len);
  395. if (Entry == NULL)
  396. {
  397. return;
  398. }
  399. if (g_MruFiles[0] == NULL)
  400. {
  401. // MRU list is empty. Delete placeholder menu entry.
  402. ClearMruMenu();
  403. }
  404. else if (g_MruFiles[MAX_MRU_FILES - 1] != NULL)
  405. {
  406. // MRU list is full, free up the oldest entry.
  407. free(g_MruFiles[MAX_MRU_FILES - 1]);
  408. }
  409. // Push entries down.
  410. memmove(g_MruFiles + 1, g_MruFiles,
  411. (MAX_MRU_FILES - 1) * sizeof(*g_MruFiles));
  412. g_MruFiles[0] = Entry;
  413. Entry->FileUse = FileUse;
  414. strcpy(Entry->FileName, File);
  415. //
  416. // Insert file in MRU menu.
  417. //
  418. MENUITEMINFO Item;
  419. ULONG i;
  420. ZeroMemory(&Item, sizeof(Item));
  421. Item.cbSize = sizeof(Item);
  422. // Renumber existing items and remove any excess.
  423. i = GetMenuItemCount(g_MruMenu);
  424. while (i-- > 0)
  425. {
  426. if (i >= MAX_MRU_FILES)
  427. {
  428. DeleteMenu(g_MruMenu, i, MF_BYPOSITION);
  429. }
  430. else
  431. {
  432. Item.fMask = MIIM_ID;
  433. GetMenuItemInfo(g_MruMenu, i, TRUE, &Item);
  434. Item.wID++;
  435. SetMenuItemInfo(g_MruMenu, i, TRUE, &Item);
  436. }
  437. }
  438. Item.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
  439. Item.fType = MFT_STRING;
  440. Item.wID = IDM_FILE_MRU_FILE1;
  441. Item.dwTypeData = g_MruFiles[0]->FileName;
  442. InsertMenuItem(g_MruMenu, 0, TRUE, &Item);
  443. DrawMenuBar(g_hwndFrame);
  444. if (g_Workspace != NULL)
  445. {
  446. g_Workspace->AddDirty(WSPF_DIRTY_MRU_LIST);
  447. }
  448. }
  449. void
  450. ClearMru(void)
  451. {
  452. ULONG i;
  453. for (i = 0; i < MAX_MRU_FILES; i++)
  454. {
  455. if (g_MruFiles[i] != NULL)
  456. {
  457. free(g_MruFiles[i]);
  458. g_MruFiles[i] = NULL;
  459. }
  460. else
  461. {
  462. break;
  463. }
  464. }
  465. ClearMruMenu();
  466. DrawMenuBar(g_hwndFrame);
  467. }
  468. ULONG
  469. GetMruSize(void)
  470. {
  471. ULONG i;
  472. ULONG Size = 0;
  473. for (i = 0; i < MAX_MRU_FILES; i++)
  474. {
  475. if (g_MruFiles[i] != NULL)
  476. {
  477. Size += MruEntrySize(g_MruFiles[i]->FileName);
  478. }
  479. else
  480. {
  481. break;
  482. }
  483. }
  484. return Size;
  485. }
  486. PUCHAR
  487. ReadMru(PUCHAR Data, PUCHAR End)
  488. {
  489. ClearMru();
  490. ULONG i;
  491. i = 0;
  492. while (Data < End)
  493. {
  494. MRU_ENTRY* DataEntry = (MRU_ENTRY*)Data;
  495. ULONG Len = MruEntrySize(DataEntry->FileName);
  496. g_MruFiles[i] = (MRU_ENTRY*)malloc(Len);
  497. if (g_MruFiles[i] == NULL)
  498. {
  499. Data = End;
  500. break;
  501. }
  502. g_MruFiles[i]->FileUse = DataEntry->FileUse;
  503. strcpy(g_MruFiles[i]->FileName, DataEntry->FileName);
  504. Data += Len;
  505. i++;
  506. }
  507. MENUITEMINFO Item;
  508. ZeroMemory(&Item, sizeof(Item));
  509. Item.cbSize = sizeof(Item);
  510. Item.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
  511. Item.fType = MFT_STRING;
  512. for (i = 0; i < MAX_MRU_FILES; i++)
  513. {
  514. if (g_MruFiles[i] == NULL)
  515. {
  516. break;
  517. }
  518. Item.wID = IDM_FILE_MRU_FILE1 + i;
  519. Item.dwTypeData = g_MruFiles[i]->FileName;
  520. InsertMenuItem(g_MruMenu, i, TRUE, &Item);
  521. }
  522. DrawMenuBar(g_hwndFrame);
  523. return Data;
  524. }
  525. PUCHAR
  526. WriteMru(PUCHAR Data)
  527. {
  528. ULONG i;
  529. for (i = 0; i < MAX_MRU_FILES; i++)
  530. {
  531. if (g_MruFiles[i] != NULL)
  532. {
  533. MRU_ENTRY* DataEntry = (MRU_ENTRY*)Data;
  534. ULONG Len = MruEntrySize(g_MruFiles[i]->FileName);
  535. DataEntry->FileUse = g_MruFiles[i]->FileUse;
  536. strcpy(DataEntry->FileName, g_MruFiles[i]->FileName);
  537. Data += Len;
  538. }
  539. else
  540. {
  541. break;
  542. }
  543. }
  544. return Data;
  545. }