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.

1080 lines
28 KiB

  1. /*++
  2. Copyright (c) 1999-2002 Microsoft Corporation
  3. Module Name:
  4. docwin.cpp
  5. Abstract:
  6. This module contains the code for the new doc windows.
  7. --*/
  8. #include "precomp.hxx"
  9. #pragma hdrstop
  10. #include <dbghelp.h>
  11. #define INVOKE_DEFAULT "notepad %f"
  12. ULONG g_TabWidth = 32;
  13. BOOL g_DisasmActivateSource;
  14. char g_EditorInvokeCommand[MAX_PATH + MAX_SOURCE_PATH] = INVOKE_DEFAULT;
  15. char g_EditorUpdateCommand[MAX_PATH + MAX_SOURCE_PATH];
  16. #define DOCWIN_CONTEXT_ID_BASE 0x100
  17. #define DOCWIN_TBB_SET_IP 0
  18. #define DOCWIN_TBB_INVOKE_EDITOR 1
  19. #define DOCWIN_TBB_COPY 2
  20. #define DOCWIN_TBB_EVAL 3
  21. #define DOCWIN_TBB_DT 4
  22. #define DOCWIN_TBB_VIEW_IP 5
  23. TBBUTTON g_DocWinTbButtons[] =
  24. {
  25. TEXT_TB_BTN(DOCWIN_TBB_SET_IP,
  26. "Set instruction pointer to current line", 0),
  27. TEXT_TB_BTN(DOCWIN_TBB_INVOKE_EDITOR, "Edit this file...", 0),
  28. TEXT_TB_BTN(DOCWIN_TBB_COPY, "Copy", 0),
  29. TEXT_TB_BTN(DOCWIN_TBB_EVAL, "Evalute selection", 0),
  30. TEXT_TB_BTN(DOCWIN_TBB_DT, "Display selected type", 0),
  31. TEXT_TB_BTN(DOCWIN_TBB_VIEW_IP, "Disassemble at current line", 0),
  32. };
  33. #define NUM_DOCWIN_MENU_BUTTONS \
  34. (sizeof(g_DocWinTbButtons) / sizeof(g_DocWinTbButtons[0]))
  35. HMENU DOCWIN_DATA::s_ContextMenu;
  36. void
  37. RunEditorCommand(PCSTR Command, PCSTR FoundFile, ULONG Line)
  38. {
  39. char RepCommand[MAX_PATH + MAX_SOURCE_PATH];
  40. PCSTR Src;
  41. PSTR Dst;
  42. if (!Command[0])
  43. {
  44. return;
  45. }
  46. Src = Command;
  47. Dst = RepCommand;
  48. while (*Src)
  49. {
  50. if (*Src == '%')
  51. {
  52. if (*(Src + 1) == 'l' ||
  53. *(Src + 1) == 'L')
  54. {
  55. // Line number.
  56. Src += 2;
  57. if ((Dst - RepCommand) + 20 >= sizeof(RepCommand))
  58. {
  59. return;
  60. }
  61. sprintf(Dst, "%d", (*(Src + 1) == 'L' ? Line : (Line + 1)));
  62. Dst += strlen(Dst);
  63. }
  64. else if (*(Src + 1) == 'f' ||
  65. *(Src + 1) == 'p')
  66. {
  67. // File name.
  68. Src += 2;
  69. if ((Dst - RepCommand) + strlen(FoundFile) >=
  70. sizeof(RepCommand))
  71. {
  72. return;
  73. }
  74. strcpy(Dst, FoundFile);
  75. Dst += strlen(Dst);
  76. }
  77. else
  78. {
  79. *Dst++ = *Src++;
  80. }
  81. }
  82. else
  83. {
  84. *Dst++ = *Src++;
  85. }
  86. }
  87. *Dst = 0;
  88. STARTUPINFOA Start;
  89. PROCESS_INFORMATION Info;
  90. ZeroMemory(&Start, sizeof(Start));
  91. Start.cb = sizeof(Start);
  92. if (CreateProcessA(NULL, RepCommand, NULL, NULL, FALSE,
  93. 0, NULL, NULL, &Start, &Info))
  94. {
  95. CloseHandle(Info.hProcess);
  96. CloseHandle(Info.hThread);
  97. }
  98. }
  99. //
  100. //
  101. //
  102. DOCWIN_DATA::DOCWIN_DATA()
  103. // State buffer isn't currently used.
  104. : EDITWIN_DATA(256)
  105. {
  106. m_enumType = DOC_WINDOW;
  107. ZeroMemory(m_FoundFile, _tsizeof(m_FoundFile));
  108. ZeroMemory(m_SymFileBuffer, _tsizeof(m_SymFileBuffer));
  109. ZeroMemory(m_PathComponent, _tsizeof(m_PathComponent));
  110. ZeroMemory(&m_LastWriteTime, sizeof(m_LastWriteTime));
  111. m_FindSel.cpMin = 1;
  112. m_FindSel.cpMax = 0;
  113. m_FindFlags = 0;
  114. }
  115. void
  116. DOCWIN_DATA::Validate()
  117. {
  118. EDITWIN_DATA::Validate();
  119. Assert(DOC_WINDOW == m_enumType);
  120. }
  121. BOOL
  122. DOCWIN_DATA::SelectedText(PTSTR Buffer, ULONG BufferChars)
  123. {
  124. return RicheditGetSelectionText(m_hwndChild, Buffer, BufferChars) > 0;
  125. }
  126. BOOL
  127. DOCWIN_DATA::CanGotoLine(void)
  128. {
  129. return m_TextLines > 0;
  130. }
  131. void
  132. DOCWIN_DATA::GotoLine(ULONG Line)
  133. {
  134. CHARRANGE Sel;
  135. Sel.cpMin = (LONG)SendMessage(m_hwndChild, EM_LINEINDEX, Line - 1, 0);
  136. Sel.cpMax = Sel.cpMin;
  137. SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&Sel);
  138. }
  139. void
  140. DOCWIN_DATA::Find(PTSTR Text, ULONG Flags, BOOL FromDlg)
  141. {
  142. RicheditFind(m_hwndChild, Text, Flags,
  143. &m_FindSel, &m_FindFlags, FromDlg);
  144. }
  145. HRESULT
  146. DOCWIN_DATA::CodeExprAtCaret(PSTR Expr, ULONG ExprSize, PULONG64 Offset)
  147. {
  148. LRESULT LineChar;
  149. LONG Line;
  150. LineChar = SendMessage(m_hwndChild, EM_LINEINDEX, -1, 0);
  151. Line = (LONG)SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0, LineChar);
  152. if (Line < 0)
  153. {
  154. return E_INVALIDARG;
  155. }
  156. // Convert to one-based.
  157. Line++;
  158. if (Expr == NULL)
  159. {
  160. // Caller is just checking whether it's possible
  161. // to get an expression or not, such as the
  162. // menu enable code. This code always considers
  163. // it possible since it can't know for sure without
  164. // a full symbol check.
  165. return S_OK;
  166. }
  167. //
  168. // First attempt to resolve the source line using currently
  169. // loaded symbols. This is done directly from the UI
  170. // thread for synchronous behavior. The assumption is
  171. // that turning off symbol loads will limit the execution
  172. // time to something reasonably quick.
  173. //
  174. DEBUG_VALUE Val;
  175. HRESULT Status;
  176. if (!PrintString(Expr, ExprSize, "@@masm(`<U>%s:%d+`)", m_SymFile, Line))
  177. {
  178. return E_INVALIDARG;
  179. }
  180. Status = g_pUiControl->Evaluate(Expr, DEBUG_VALUE_INT64, &Val, NULL);
  181. // Don't preserve the <U>nqualified option in the actual
  182. // expression returned as it's just a temporary override.
  183. sprintf(Expr, "@@masm(`%s:%d+`)", m_SymFile, Line);
  184. if (Status == S_OK)
  185. {
  186. if (Offset != NULL)
  187. {
  188. *Offset = Val.I64;
  189. }
  190. return S_OK;
  191. }
  192. ULONG SymOpts;
  193. if (g_pUiSymbols->GetSymbolOptions(&SymOpts) == S_OK &&
  194. (SymOpts & SYMOPT_NO_UNQUALIFIED_LOADS))
  195. {
  196. // The user isn't allowing unqualified loads so
  197. // further searches won't help.
  198. return E_NOINTERFACE;
  199. }
  200. // We weren't able to resolve the expression with the
  201. // existing symbols so we'll need to do a full search.
  202. // This can be very expensive, so allow the user to cancel.
  203. if (g_QuietMode == QMODE_DISABLED)
  204. {
  205. int Mode = QuestionBox(STR_Unresolved_Source_Expr, MB_YESNOCANCEL);
  206. if (Mode == IDCANCEL)
  207. {
  208. return E_NOINTERFACE;
  209. }
  210. else if (Mode == IDYES)
  211. {
  212. if (g_pUiControl->Evaluate(Expr, DEBUG_VALUE_INT64,
  213. &Val, NULL) == S_OK)
  214. {
  215. if (Offset != NULL)
  216. {
  217. *Offset = Val.I64;
  218. }
  219. return S_OK;
  220. }
  221. else
  222. {
  223. return E_NOINTERFACE;
  224. }
  225. }
  226. }
  227. // Let the expression go without trying to further resolve it.
  228. if (Offset != NULL)
  229. {
  230. *Offset = DEBUG_INVALID_OFFSET;
  231. }
  232. return S_FALSE;
  233. }
  234. void
  235. DOCWIN_DATA::ToggleBpAtCaret(void)
  236. {
  237. HRESULT Status;
  238. LRESULT LineChar;
  239. LONG Line;
  240. LineChar = SendMessage(m_hwndChild, EM_LINEINDEX, -1, 0);
  241. Line = (LONG)SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0, LineChar);
  242. if (Line < 0)
  243. {
  244. return;
  245. }
  246. // If we have a breakpoint on this line remove it.
  247. EDIT_HIGHLIGHT* Hl = GetLineHighlighting(Line);
  248. if (Hl != NULL && (Hl->Flags & EHL_ANY_BP))
  249. {
  250. PrintStringCommand(UIC_SILENT_EXECUTE, "bc %d", (ULONG)Hl->Data);
  251. return;
  252. }
  253. //
  254. // No breakpoint exists so add a new one.
  255. //
  256. char CodeExpr[MAX_OFFSET_EXPR];
  257. ULONG64 Offset;
  258. Status = CodeExprAtCaret(CodeExpr, DIMA(CodeExpr), &Offset);
  259. if (FAILED(Status))
  260. {
  261. MessageBeep(0);
  262. ErrorBox(NULL, 0, ERR_No_Code_For_File_Line);
  263. }
  264. else
  265. {
  266. if (Status == S_OK)
  267. {
  268. char SymName[MAX_OFFSET_EXPR];
  269. ULONG64 Disp;
  270. // Check and see whether this offset maps
  271. // exactly to a symbol. If it does, use
  272. // the symbol name to be more robust in the
  273. // face of source changes.
  274. // Symbols should be loaded at this point since
  275. // we just used them to resolve the source
  276. // expression that produced Offset, so we
  277. // can safely do this on the UI thread.
  278. if (g_pUiSymbols->GetNameByOffset(Offset, SymName, sizeof(SymName),
  279. NULL, &Disp) == S_OK &&
  280. Disp == 0)
  281. {
  282. strcpy(CodeExpr, SymName);
  283. }
  284. }
  285. PrintStringCommand(UIC_SILENT_EXECUTE, "bu %s", CodeExpr);
  286. }
  287. }
  288. HMENU
  289. DOCWIN_DATA::GetContextMenu(void)
  290. {
  291. return s_ContextMenu;
  292. }
  293. void
  294. DOCWIN_DATA::OnContextMenuSelection(UINT Item)
  295. {
  296. CHARRANGE Sel;
  297. int Line;
  298. TCHAR SelText[256];
  299. Item -= DOCWIN_CONTEXT_ID_BASE;
  300. switch(Item)
  301. {
  302. case DOCWIN_TBB_SET_IP:
  303. SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&Sel);
  304. Line = (int)
  305. SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0, Sel.cpMin);
  306. PrintStringCommand(UIC_SET_IP, "r$ip = @@masm(`%s:%d+`)",
  307. m_SymFile, Line + 1);
  308. break;
  309. case DOCWIN_TBB_INVOKE_EDITOR:
  310. SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&Sel);
  311. Line = (int)
  312. SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0, Sel.cpMin);
  313. RunEditorCommand(g_EditorInvokeCommand, m_FoundFile, Line);
  314. break;
  315. case DOCWIN_TBB_COPY:
  316. SendMessage(m_hwndChild, WM_COPY, 0, 0);
  317. break;
  318. case DOCWIN_TBB_EVAL:
  319. SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&Sel);
  320. if (Sel.cpMax > Sel.cpMin)
  321. {
  322. if (!RicheditGetSelectionText(m_hwndChild, SelText, DIMA(SelText)))
  323. {
  324. break;
  325. }
  326. }
  327. else if (!RicheditGetSourceToken(m_hwndChild, SelText, DIMA(SelText),
  328. &Sel))
  329. {
  330. break;
  331. }
  332. PrintStringCommand(UIC_EXECUTE, "?? %s", SelText);
  333. break;
  334. case DOCWIN_TBB_DT:
  335. SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&Sel);
  336. if (Sel.cpMax > Sel.cpMin)
  337. {
  338. if (!RicheditGetSelectionText(m_hwndChild, SelText, DIMA(SelText)))
  339. {
  340. break;
  341. }
  342. }
  343. else if (!RicheditGetSourceToken(m_hwndChild, SelText, DIMA(SelText),
  344. &Sel))
  345. {
  346. break;
  347. }
  348. PrintStringCommand(UIC_EXECUTE, "dt %s", SelText);
  349. break;
  350. case DOCWIN_TBB_VIEW_IP:
  351. SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&Sel);
  352. Line = (int)
  353. SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0, Sel.cpMin);
  354. PrintStringCommand(UIC_DISPLAY_CODE_EXPR, "@@masm(`%s:%d+`)",
  355. m_SymFile, Line + 1);
  356. break;
  357. }
  358. }
  359. BOOL
  360. DOCWIN_DATA::OnCreate(void)
  361. {
  362. if (s_ContextMenu == NULL &&
  363. g_EditorInvokeCommand)
  364. {
  365. s_ContextMenu = CreateContextMenuFromToolbarButtons
  366. (NUM_DOCWIN_MENU_BUTTONS, g_DocWinTbButtons,
  367. DOCWIN_CONTEXT_ID_BASE);
  368. if (s_ContextMenu == NULL)
  369. {
  370. return FALSE;
  371. }
  372. }
  373. if (!EDITWIN_DATA::OnCreate())
  374. {
  375. return FALSE;
  376. }
  377. SendMessage(m_hwndChild, EM_SETEDITSTYLE,
  378. SES_XLTCRCRLFTOCR, SES_XLTCRCRLFTOCR);
  379. SendMessage(m_hwndChild, EM_SETEVENTMASK,
  380. 0, ENM_SELCHANGE | ENM_KEYEVENTS | ENM_MOUSEEVENTS);
  381. SendMessage(m_hwndChild, EM_SETTABSTOPS, 1, (LPARAM)&g_TabWidth);
  382. return TRUE;
  383. }
  384. LRESULT
  385. DOCWIN_DATA::OnNotify(WPARAM Wpm, LPARAM Lpm)
  386. {
  387. NMHDR* Hdr = (NMHDR*)Lpm;
  388. if (Hdr->code == EN_SELCHANGE)
  389. {
  390. SELCHANGE* SelChange = (SELCHANGE*)Lpm;
  391. int Line = (int)
  392. SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0,
  393. SelChange->chrg.cpMin);
  394. LRESULT LineFirst =
  395. SendMessage(m_hwndChild, EM_LINEINDEX, Line, 0);
  396. SetLineColumn_StatusBar(Line + 1,
  397. (int)(SelChange->chrg.cpMin - LineFirst) + 1);
  398. return 0;
  399. }
  400. else if (Hdr->code == EN_MSGFILTER)
  401. {
  402. MSGFILTER* Filter = (MSGFILTER*)Lpm;
  403. char Token[256];
  404. CHARRANGE TokenRange;
  405. if (Filter->msg == WM_LBUTTONDBLCLK &&
  406. RicheditGetSourceToken(m_hwndChild, Token, DIMA(Token),
  407. &TokenRange))
  408. {
  409. SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&TokenRange);
  410. return 1;
  411. }
  412. }
  413. return EDITWIN_DATA::OnNotify(Wpm, Lpm);
  414. }
  415. void
  416. DOCWIN_DATA::OnUpdate(
  417. UpdateType Type
  418. )
  419. {
  420. if (Type == UPDATE_BP ||
  421. Type == UPDATE_BUFFER ||
  422. Type == UPDATE_END_SESSION)
  423. {
  424. UpdateBpMarks();
  425. }
  426. else if (Type == UPDATE_START_SESSION ||
  427. Type == UPDATE_REFRESH_MODULES)
  428. {
  429. // If there's already a message box open we don't
  430. // want to put up a new one. This may mean we
  431. // miss a source file change but it should be relatively
  432. // uncommon. If it's a problem we could start up a timer
  433. // to repost the update later.
  434. if (g_nBoxCount == 0 &&
  435. m_FoundFile[0] &&
  436. CheckForFileChanges(m_FoundFile, &m_LastWriteTime) == IDYES)
  437. {
  438. char Found[MAX_SOURCE_PATH], Sym[MAX_SOURCE_PATH];
  439. char PathComp[MAX_SOURCE_PATH];
  440. // Save away filenames since they're copied over
  441. // on a successful load.
  442. strcpy(Found, m_FoundFile);
  443. strcpy(Sym, m_SymFileBuffer);
  444. strcpy(PathComp, m_PathComponent);
  445. if (!LoadFile(Found, Sym, PathComp))
  446. {
  447. PostMessage(g_hwndMDIClient, WM_MDIDESTROY, (WPARAM)m_Win, 0);
  448. }
  449. }
  450. }
  451. }
  452. ULONG
  453. DOCWIN_DATA::GetWorkspaceSize(void)
  454. {
  455. ULONG Len = EDITWIN_DATA::GetWorkspaceSize();
  456. Len += _tcslen(m_FoundFile) + 1;
  457. Len += _tcslen(m_SymFileBuffer) + 1;
  458. Len += _tcslen(m_PathComponent) + 1;
  459. Len += sizeof(LONG);
  460. return Len;
  461. }
  462. PUCHAR
  463. DOCWIN_DATA::SetWorkspace(PUCHAR Data)
  464. {
  465. PTSTR Str = (PTSTR)EDITWIN_DATA::SetWorkspace(Data);
  466. _tcscpy(Str, m_FoundFile);
  467. Str += _tcslen(m_FoundFile) + 1;
  468. _tcscpy(Str, m_SymFileBuffer);
  469. Str += _tcslen(m_SymFileBuffer) + 1;
  470. _tcscpy(Str, m_PathComponent);
  471. Str += _tcslen(m_PathComponent) + 1;
  472. CHARRANGE Sel;
  473. SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&Sel);
  474. *(LONG UNALIGNED *)Str = Sel.cpMin;
  475. Str += sizeof(Sel.cpMin);
  476. return (PUCHAR)Str;
  477. }
  478. PUCHAR
  479. DOCWIN_DATA::ApplyWorkspace1(PUCHAR Data, PUCHAR End)
  480. {
  481. PTSTR Found = (PTSTR)EDITWIN_DATA::ApplyWorkspace1(Data, End);
  482. PTSTR Sym = Found + _tcslen(Found) + 1;
  483. PTSTR SymEnd = Sym + _tcslen(Sym) + 1;
  484. PTSTR PathComp = SymEnd;
  485. if ((PUCHAR)PathComp >= End || !PathComp[0])
  486. {
  487. PathComp = NULL;
  488. }
  489. if ((PUCHAR)SymEnd >= End)
  490. {
  491. Data = (PUCHAR)SymEnd;
  492. }
  493. else
  494. {
  495. Data = (PUCHAR)(SymEnd + _tcslen(SymEnd) + 1);
  496. }
  497. if (Found[0])
  498. {
  499. if (FindDocWindowByFileName(Found, NULL, NULL) ||
  500. !LoadFile(Found, Sym[0] ? Sym : NULL, PathComp))
  501. {
  502. PostMessage(g_hwndMDIClient, WM_MDIDESTROY, (WPARAM)m_Win, 0);
  503. }
  504. }
  505. if (Data < End)
  506. {
  507. CHARRANGE Sel;
  508. Sel.cpMin = *(LONG UNALIGNED *)Data;
  509. Sel.cpMax = Sel.cpMin;
  510. SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&Sel);
  511. SendMessage(m_hwndChild, EM_SCROLLCARET, 0, 0);
  512. Data += sizeof(Sel.cpMin);
  513. }
  514. return Data;
  515. }
  516. void
  517. DOCWIN_DATA::UpdateBpMarks(void)
  518. {
  519. if (m_TextLines == 0 ||
  520. g_BpBuffer->UiLockForRead() != S_OK)
  521. {
  522. return;
  523. }
  524. SendMessage(m_hwndChild, WM_SETREDRAW, FALSE, 0);
  525. // Remove existing BP highlights.
  526. RemoveAllHighlights(EHL_ANY_BP);
  527. //
  528. // Highlight every line that matches a breakpoint.
  529. //
  530. BpBufferData* BpData = (BpBufferData*)g_BpBuffer->GetDataBuffer();
  531. ULONG i;
  532. for (i = 0; i < g_BpCount; i++)
  533. {
  534. if (BpData[i].FileOffset)
  535. {
  536. PSTR FileSpace;
  537. ULONG Line;
  538. PSTR FileStop, MatchStop;
  539. ULONG HlFlags;
  540. FileSpace = (PSTR)g_BpBuffer->GetDataBuffer() +
  541. BpData[i].FileOffset;
  542. // Adjust to zero-based.
  543. Line = *(ULONG UNALIGNED *)FileSpace - 1;
  544. FileSpace += sizeof(Line);
  545. // If this document's file matches some suffix
  546. // of the breakpoint's file at the path component
  547. // level then do the highlight. This can result in
  548. // extra highlights for multiple files with the same
  549. // name but in different directories. That's a rare
  550. // enough problem to wait for somebody to complain
  551. // before trying to hack some better check up.
  552. if (SymMatchFileName(FileSpace, (PSTR)m_SymFile,
  553. &FileStop, &MatchStop) ||
  554. *MatchStop == '\\' ||
  555. *MatchStop == '/' ||
  556. *MatchStop == ':')
  557. {
  558. if (BpData[i].Flags & DEBUG_BREAKPOINT_ENABLED)
  559. {
  560. HlFlags = EHL_ENABLED_BP;
  561. }
  562. else
  563. {
  564. HlFlags = EHL_DISABLED_BP;
  565. }
  566. EDIT_HIGHLIGHT* Hl = AddHighlight(Line, HlFlags);
  567. if (Hl != NULL)
  568. {
  569. Hl->Data = BpData[i].Id;
  570. }
  571. }
  572. }
  573. }
  574. UnlockStateBuffer(g_BpBuffer);
  575. SendMessage(m_hwndChild, WM_SETREDRAW, TRUE, 0);
  576. InvalidateRect(m_hwndChild, NULL, TRUE);
  577. }
  578. DWORD
  579. CALLBACK
  580. EditStreamCallback(
  581. DWORD_PTR dwFileHandle, // application-defined value
  582. LPBYTE pbBuff, // data buffer
  583. LONG cb, // number of bytes to read or write
  584. LONG *pcb // number of bytes transferred
  585. )
  586. {
  587. HRESULT Status;
  588. PathFile* File = (PathFile*)dwFileHandle;
  589. if ((Status = File->Read(pbBuff, cb, (PDWORD)pcb)) != S_OK)
  590. {
  591. return Status;
  592. }
  593. // Edit out page-break characters (^L's) as richedit
  594. // gives them their own line which throws off line numbers.
  595. while (cb-- > 0)
  596. {
  597. if (*pbBuff == '\f')
  598. {
  599. *pbBuff = ' ';
  600. }
  601. pbBuff++;
  602. }
  603. return 0; // No error
  604. }
  605. BOOL
  606. DOCWIN_DATA::LoadFile(
  607. PCTSTR pszFoundFile,
  608. PCTSTR pszSymFile,
  609. PCTSTR pszPathComponent
  610. )
  611. /*++
  612. Returns
  613. TRUE - Success, file opened and loaded
  614. FALSE - Failure, file not loaded
  615. --*/
  616. {
  617. Assert(pszFoundFile);
  618. BOOL bRet = TRUE;
  619. HCURSOR hcursor = NULL;
  620. EDITSTREAM editstr = {0};
  621. PathFile *File = NULL;
  622. if ((OpenPathFile(pszPathComponent, pszFoundFile, 0, &File)) != S_OK)
  623. {
  624. ErrorBox(NULL, 0, ERR_File_Open, pszFoundFile);
  625. bRet = FALSE;
  626. goto exit;
  627. }
  628. // Store last write time to check for file changes.
  629. if (File->GetLastWriteTime(&m_LastWriteTime) != S_OK)
  630. {
  631. ZeroMemory(&m_LastWriteTime, sizeof(m_LastWriteTime));
  632. }
  633. // Set the Hour glass cursor
  634. hcursor = SetCursor( LoadCursor(NULL, IDC_WAIT) );
  635. // Select all of the text so that it will be replaced
  636. SendMessage(m_hwndChild, EM_SETSEL, 0, -1);
  637. // Put the text into the window
  638. editstr.dwCookie = (DWORD_PTR)File;
  639. editstr.pfnCallback = EditStreamCallback;
  640. SendMessage(m_hwndChild,
  641. EM_STREAMIN,
  642. SF_TEXT,
  643. (LPARAM) &editstr
  644. );
  645. RicheditUpdateColors(m_hwndChild,
  646. g_Colors[COL_PLAIN_TEXT].Color, TRUE,
  647. g_Colors[COL_PLAIN].Color, TRUE);
  648. // Restore cursor
  649. SetCursor(hcursor);
  650. _tcsncpy(m_FoundFile, pszFoundFile, _tsizeof(m_FoundFile) - 1 );
  651. m_FoundFile[ _tsizeof(m_FoundFile) - 1 ] = 0;
  652. if (pszSymFile != NULL && pszSymFile[0])
  653. {
  654. _tcsncpy(m_SymFileBuffer, pszSymFile, _tsizeof(m_SymFileBuffer) - 1 );
  655. m_SymFileBuffer[ _tsizeof(m_SymFileBuffer) - 1 ] = 0;
  656. m_SymFile = m_SymFileBuffer;
  657. }
  658. else
  659. {
  660. // No symbol file information so just use the found filename.
  661. m_SymFileBuffer[0] = 0;
  662. m_SymFile = strrchr(m_FoundFile, '\\');
  663. if (m_SymFile == NULL)
  664. {
  665. m_SymFile = strrchr(m_FoundFile, '/');
  666. if (m_SymFile == NULL)
  667. {
  668. m_SymFile = strrchr(m_FoundFile, ':');
  669. if (m_SymFile == NULL)
  670. {
  671. m_SymFile = m_FoundFile - 1;
  672. }
  673. }
  674. }
  675. m_SymFile++;
  676. }
  677. if (pszPathComponent)
  678. {
  679. _tcsncpy(m_PathComponent, pszPathComponent,
  680. _tsizeof(m_PathComponent) - 1);
  681. m_PathComponent[_tsizeof(m_PathComponent) - 1] = 0;
  682. }
  683. else
  684. {
  685. m_PathComponent[0] = 0;
  686. }
  687. SetWindowText(m_Win, m_FoundFile);
  688. if (SendMessage(m_hwndChild, WM_GETTEXTLENGTH, 0, 0) == 0)
  689. {
  690. m_TextLines = 0;
  691. }
  692. else
  693. {
  694. m_TextLines = (ULONG)SendMessage(m_hwndChild, EM_GETLINECOUNT, 0, 0);
  695. }
  696. if (g_LineMarkers)
  697. {
  698. // Insert marker space before every line.
  699. for (ULONG i = 0; i < m_TextLines; i++)
  700. {
  701. CHARRANGE Ins;
  702. Ins.cpMin = (LONG)SendMessage(m_hwndChild, EM_LINEINDEX, i, 0);
  703. Ins.cpMax = Ins.cpMin;
  704. SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&Ins);
  705. SendMessage(m_hwndChild, EM_REPLACESEL, FALSE, (LPARAM)" ");
  706. }
  707. }
  708. // Request that the engine update the line map for the file.
  709. UiRequestRead();
  710. exit:
  711. delete File;
  712. return bRet;
  713. }
  714. BOOL
  715. SameFileName(PCSTR Name1, PCSTR Name2)
  716. {
  717. while (*Name1)
  718. {
  719. if (!(((*Name1 == '\\' || *Name1 == '/') &&
  720. (*Name2 == '\\' || *Name2 == '/')) ||
  721. toupper(*Name1) == toupper(*Name2)))
  722. {
  723. return FALSE;
  724. }
  725. Name1++;
  726. Name2++;
  727. }
  728. return *Name2 == 0;
  729. }
  730. BOOL
  731. FindDocWindowByFileName(
  732. IN PCTSTR pszFile,
  733. OPTIONAL HWND *phwnd,
  734. OPTIONAL PDOCWIN_DATA *ppDocWinData
  735. )
  736. /*++
  737. Returns
  738. TRUE - If the window is currently open.
  739. FALSE - Not currently open.
  740. --*/
  741. {
  742. Assert(pszFile);
  743. PLIST_ENTRY Entry;
  744. PDOCWIN_DATA pTmp;
  745. Entry = g_ActiveWin.Flink;
  746. while (Entry != &g_ActiveWin)
  747. {
  748. pTmp = (PDOCWIN_DATA)ACTIVE_WIN_ENTRY(Entry);
  749. if ( pTmp->m_enumType == DOC_WINDOW &&
  750. SameFileName(pTmp->m_FoundFile, pszFile) )
  751. {
  752. if (ppDocWinData)
  753. {
  754. *ppDocWinData = pTmp;
  755. }
  756. if (phwnd)
  757. {
  758. *phwnd = pTmp->m_Win;
  759. }
  760. return TRUE;
  761. }
  762. Entry = Entry->Flink;
  763. }
  764. return FALSE;
  765. }
  766. BOOL
  767. OpenOrActivateFile(PCSTR FoundFile, PCSTR SymFile, PCSTR PathComponent,
  768. ULONG Line, BOOL Activate, BOOL UserActivated)
  769. {
  770. HWND hwndDoc = NULL;
  771. PDOCWIN_DATA pDoc;
  772. BOOL Activated = FALSE;
  773. if ( FindDocWindowByFileName( FoundFile, &hwndDoc, &pDoc) )
  774. {
  775. if (Activate)
  776. {
  777. // Found it. Now activate it.
  778. if (IsIconic(hwndDoc))
  779. {
  780. ShowWindow(hwndDoc, SW_RESTORE);
  781. }
  782. ActivateMDIChild(hwndDoc, UserActivated);
  783. Activated = TRUE;
  784. }
  785. }
  786. else
  787. {
  788. HWND WinTop, WinUnder;
  789. WinTop = MDIGetActive(g_hwndMDIClient, NULL);
  790. if (WinTop)
  791. {
  792. WinUnder = GetNextWindow(WinTop, GW_HWNDNEXT);
  793. }
  794. else
  795. {
  796. WinUnder = NULL;
  797. }
  798. hwndDoc = NewDoc_CreateWindow(g_hwndMDIClient);
  799. if (hwndDoc == NULL)
  800. {
  801. return FALSE;
  802. }
  803. pDoc = GetDocWinData(hwndDoc);
  804. Assert(pDoc);
  805. if (!pDoc->LoadFile(FoundFile, SymFile, PathComponent))
  806. {
  807. DestroyWindow(pDoc->m_Win);
  808. return FALSE;
  809. }
  810. if (!UserActivated && WinTop)
  811. {
  812. // If this isn't a user-provoked activation we don't
  813. // want the window to obscure the user's current window.
  814. // Reorder the current windows appropriately.
  815. ReorderChildren(WinUnder, WinTop, pDoc->m_Win,
  816. UserActivated);
  817. }
  818. Activated = TRUE;
  819. }
  820. // Success. Now highlight the line.
  821. pDoc->SetCurrentLineHighlight(Line);
  822. return Activated;
  823. }
  824. void
  825. UpdateCodeDisplay(
  826. ULONG64 Ip,
  827. PCSTR FoundFile,
  828. PCSTR SymFile,
  829. PCSTR PathComponent,
  830. ULONG Line,
  831. BOOL UserActivated
  832. )
  833. {
  834. // Update the disassembly window if there's one
  835. // active or there's no source information.
  836. BOOL Activated = FALSE;
  837. HWND hwndDisasm = GetDisasmHwnd();
  838. if (hwndDisasm == NULL && FoundFile == NULL &&
  839. (g_WinOptions & WOPT_AUTO_DISASM))
  840. {
  841. // No disassembly window around and no source so create one.
  842. hwndDisasm = NewDisasm_CreateWindow(g_hwndMDIClient);
  843. }
  844. if (hwndDisasm != NULL)
  845. {
  846. PDISASMWIN_DATA pDis = GetDisasmWinData(hwndDisasm);
  847. Assert(pDis);
  848. pDis->SetCurInstr(Ip);
  849. }
  850. if (FoundFile != NULL)
  851. {
  852. //
  853. // We now know the file name and line number. Either
  854. // it's open or we open it.
  855. //
  856. Activated = OpenOrActivateFile(FoundFile, SymFile, PathComponent, Line,
  857. GetSrcMode_StatusBar() ||
  858. g_DisasmActivateSource,
  859. UserActivated);
  860. RunEditorCommand(g_EditorUpdateCommand, FoundFile, Line);
  861. }
  862. else
  863. {
  864. // No source file was found so make sure no
  865. // doc windows have a highlight.
  866. EDITWIN_DATA::RemoveActiveWinHighlights(1 << DOC_WINDOW,
  867. EHL_CURRENT_LINE);
  868. }
  869. if ((!Activated || !GetSrcMode_StatusBar()) && hwndDisasm != NULL)
  870. {
  871. // No window has been activated yet so fall back
  872. // on activating the disassembly window.
  873. ActivateMDIChild(hwndDisasm, UserActivated);
  874. }
  875. }
  876. void
  877. SetTabWidth(ULONG TabWidth)
  878. {
  879. PLIST_ENTRY Entry;
  880. PDOCWIN_DATA DocData;
  881. g_TabWidth = TabWidth;
  882. if (g_Workspace != NULL)
  883. {
  884. g_Workspace->SetUlong(WSP_GLOBAL_TAB_WIDTH, TabWidth);
  885. }
  886. Entry = g_ActiveWin.Flink;
  887. while (Entry != &g_ActiveWin)
  888. {
  889. DocData = (PDOCWIN_DATA)ACTIVE_WIN_ENTRY(Entry);
  890. if (DocData->m_enumType == DOC_WINDOW)
  891. {
  892. SendMessage(DocData->m_hwndChild, EM_SETTABSTOPS,
  893. 1, (LPARAM)&g_TabWidth);
  894. }
  895. Entry = Entry->Flink;
  896. }
  897. }
  898. void
  899. GetEditorCommandDefaults(void)
  900. {
  901. PSTR Env;
  902. HKEY Key;
  903. // As a convenience for windiff users pick up the
  904. // windiff editor registry setting.
  905. if (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windiff",
  906. 0, KEY_READ, &Key) == ERROR_SUCCESS)
  907. {
  908. DWORD Type;
  909. DWORD Size;
  910. Size = sizeof(g_EditorInvokeCommand);
  911. if (RegQueryValueExA(Key, "Editor", NULL, &Type,
  912. (LPBYTE)g_EditorInvokeCommand,
  913. &Size) != ERROR_SUCCESS ||
  914. Type != REG_SZ)
  915. {
  916. strcpy(g_EditorInvokeCommand, INVOKE_DEFAULT);
  917. }
  918. RegCloseKey(Key);
  919. }
  920. Env = getenv("WINDBG_INVOKE_EDITOR");
  921. if (Env)
  922. {
  923. CopyString(g_EditorInvokeCommand, Env, DIMA(g_EditorInvokeCommand));
  924. }
  925. Env = getenv("WINDBG_UPDATE_EDITOR");
  926. if (Env)
  927. {
  928. CopyString(g_EditorUpdateCommand, Env, DIMA(g_EditorInvokeCommand));
  929. }
  930. }