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.

688 lines
16 KiB

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