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

/*++
Copyright (c) 1999-2002 Microsoft Corporation
Module Name:
docwin.cpp
Abstract:
This module contains the code for the new doc windows.
--*/
#include "precomp.hxx"
#pragma hdrstop
#include <dbghelp.h>
#define INVOKE_DEFAULT "notepad %f"
ULONG g_TabWidth = 32;
BOOL g_DisasmActivateSource;
char g_EditorInvokeCommand[MAX_PATH + MAX_SOURCE_PATH] = INVOKE_DEFAULT;
char g_EditorUpdateCommand[MAX_PATH + MAX_SOURCE_PATH];
#define DOCWIN_CONTEXT_ID_BASE 0x100
#define DOCWIN_TBB_SET_IP 0
#define DOCWIN_TBB_INVOKE_EDITOR 1
#define DOCWIN_TBB_COPY 2
#define DOCWIN_TBB_EVAL 3
#define DOCWIN_TBB_DT 4
#define DOCWIN_TBB_VIEW_IP 5
TBBUTTON g_DocWinTbButtons[] =
{
TEXT_TB_BTN(DOCWIN_TBB_SET_IP,
"Set instruction pointer to current line", 0),
TEXT_TB_BTN(DOCWIN_TBB_INVOKE_EDITOR, "Edit this file...", 0),
TEXT_TB_BTN(DOCWIN_TBB_COPY, "Copy", 0),
TEXT_TB_BTN(DOCWIN_TBB_EVAL, "Evalute selection", 0),
TEXT_TB_BTN(DOCWIN_TBB_DT, "Display selected type", 0),
TEXT_TB_BTN(DOCWIN_TBB_VIEW_IP, "Disassemble at current line", 0),
};
#define NUM_DOCWIN_MENU_BUTTONS \
(sizeof(g_DocWinTbButtons) / sizeof(g_DocWinTbButtons[0]))
HMENU DOCWIN_DATA::s_ContextMenu;
void
RunEditorCommand(PCSTR Command, PCSTR FoundFile, ULONG Line)
{
char RepCommand[MAX_PATH + MAX_SOURCE_PATH];
PCSTR Src;
PSTR Dst;
if (!Command[0])
{
return;
}
Src = Command;
Dst = RepCommand;
while (*Src)
{
if (*Src == '%')
{
if (*(Src + 1) == 'l' ||
*(Src + 1) == 'L')
{
// Line number.
Src += 2;
if ((Dst - RepCommand) + 20 >= sizeof(RepCommand))
{
return;
}
sprintf(Dst, "%d", (*(Src + 1) == 'L' ? Line : (Line + 1)));
Dst += strlen(Dst);
}
else if (*(Src + 1) == 'f' ||
*(Src + 1) == 'p')
{
// File name.
Src += 2;
if ((Dst - RepCommand) + strlen(FoundFile) >=
sizeof(RepCommand))
{
return;
}
strcpy(Dst, FoundFile);
Dst += strlen(Dst);
}
else
{
*Dst++ = *Src++;
}
}
else
{
*Dst++ = *Src++;
}
}
*Dst = 0;
STARTUPINFOA Start;
PROCESS_INFORMATION Info;
ZeroMemory(&Start, sizeof(Start));
Start.cb = sizeof(Start);
if (CreateProcessA(NULL, RepCommand, NULL, NULL, FALSE,
0, NULL, NULL, &Start, &Info))
{
CloseHandle(Info.hProcess);
CloseHandle(Info.hThread);
}
}
//
//
//
DOCWIN_DATA::DOCWIN_DATA()
// State buffer isn't currently used.
: EDITWIN_DATA(256)
{
m_enumType = DOC_WINDOW;
ZeroMemory(m_FoundFile, _tsizeof(m_FoundFile));
ZeroMemory(m_SymFileBuffer, _tsizeof(m_SymFileBuffer));
ZeroMemory(m_PathComponent, _tsizeof(m_PathComponent));
ZeroMemory(&m_LastWriteTime, sizeof(m_LastWriteTime));
m_FindSel.cpMin = 1;
m_FindSel.cpMax = 0;
m_FindFlags = 0;
}
void
DOCWIN_DATA::Validate()
{
EDITWIN_DATA::Validate();
Assert(DOC_WINDOW == m_enumType);
}
BOOL
DOCWIN_DATA::SelectedText(PTSTR Buffer, ULONG BufferChars)
{
return RicheditGetSelectionText(m_hwndChild, Buffer, BufferChars) > 0;
}
BOOL
DOCWIN_DATA::CanGotoLine(void)
{
return m_TextLines > 0;
}
void
DOCWIN_DATA::GotoLine(ULONG Line)
{
CHARRANGE Sel;
Sel.cpMin = (LONG)SendMessage(m_hwndChild, EM_LINEINDEX, Line - 1, 0);
Sel.cpMax = Sel.cpMin;
SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&Sel);
}
void
DOCWIN_DATA::Find(PTSTR Text, ULONG Flags, BOOL FromDlg)
{
RicheditFind(m_hwndChild, Text, Flags,
&m_FindSel, &m_FindFlags, FromDlg);
}
HRESULT
DOCWIN_DATA::CodeExprAtCaret(PSTR Expr, ULONG ExprSize, PULONG64 Offset)
{
LRESULT LineChar;
LONG Line;
LineChar = SendMessage(m_hwndChild, EM_LINEINDEX, -1, 0);
Line = (LONG)SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0, LineChar);
if (Line < 0)
{
return E_INVALIDARG;
}
// Convert to one-based.
Line++;
if (Expr == NULL)
{
// Caller is just checking whether it's possible
// to get an expression or not, such as the
// menu enable code. This code always considers
// it possible since it can't know for sure without
// a full symbol check.
return S_OK;
}
//
// First attempt to resolve the source line using currently
// loaded symbols. This is done directly from the UI
// thread for synchronous behavior. The assumption is
// that turning off symbol loads will limit the execution
// time to something reasonably quick.
//
DEBUG_VALUE Val;
HRESULT Status;
if (!PrintString(Expr, ExprSize, "@@masm(`<U>%s:%d+`)", m_SymFile, Line))
{
return E_INVALIDARG;
}
Status = g_pUiControl->Evaluate(Expr, DEBUG_VALUE_INT64, &Val, NULL);
// Don't preserve the <U>nqualified option in the actual
// expression returned as it's just a temporary override.
sprintf(Expr, "@@masm(`%s:%d+`)", m_SymFile, Line);
if (Status == S_OK)
{
if (Offset != NULL)
{
*Offset = Val.I64;
}
return S_OK;
}
ULONG SymOpts;
if (g_pUiSymbols->GetSymbolOptions(&SymOpts) == S_OK &&
(SymOpts & SYMOPT_NO_UNQUALIFIED_LOADS))
{
// The user isn't allowing unqualified loads so
// further searches won't help.
return E_NOINTERFACE;
}
// We weren't able to resolve the expression with the
// existing symbols so we'll need to do a full search.
// This can be very expensive, so allow the user to cancel.
if (g_QuietMode == QMODE_DISABLED)
{
int Mode = QuestionBox(STR_Unresolved_Source_Expr, MB_YESNOCANCEL);
if (Mode == IDCANCEL)
{
return E_NOINTERFACE;
}
else if (Mode == IDYES)
{
if (g_pUiControl->Evaluate(Expr, DEBUG_VALUE_INT64,
&Val, NULL) == S_OK)
{
if (Offset != NULL)
{
*Offset = Val.I64;
}
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
}
// Let the expression go without trying to further resolve it.
if (Offset != NULL)
{
*Offset = DEBUG_INVALID_OFFSET;
}
return S_FALSE;
}
void
DOCWIN_DATA::ToggleBpAtCaret(void)
{
HRESULT Status;
LRESULT LineChar;
LONG Line;
LineChar = SendMessage(m_hwndChild, EM_LINEINDEX, -1, 0);
Line = (LONG)SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0, LineChar);
if (Line < 0)
{
return;
}
// If we have a breakpoint on this line remove it.
EDIT_HIGHLIGHT* Hl = GetLineHighlighting(Line);
if (Hl != NULL && (Hl->Flags & EHL_ANY_BP))
{
PrintStringCommand(UIC_SILENT_EXECUTE, "bc %d", (ULONG)Hl->Data);
return;
}
//
// No breakpoint exists so add a new one.
//
char CodeExpr[MAX_OFFSET_EXPR];
ULONG64 Offset;
Status = CodeExprAtCaret(CodeExpr, DIMA(CodeExpr), &Offset);
if (FAILED(Status))
{
MessageBeep(0);
ErrorBox(NULL, 0, ERR_No_Code_For_File_Line);
}
else
{
if (Status == S_OK)
{
char SymName[MAX_OFFSET_EXPR];
ULONG64 Disp;
// Check and see whether this offset maps
// exactly to a symbol. If it does, use
// the symbol name to be more robust in the
// face of source changes.
// Symbols should be loaded at this point since
// we just used them to resolve the source
// expression that produced Offset, so we
// can safely do this on the UI thread.
if (g_pUiSymbols->GetNameByOffset(Offset, SymName, sizeof(SymName),
NULL, &Disp) == S_OK &&
Disp == 0)
{
strcpy(CodeExpr, SymName);
}
}
PrintStringCommand(UIC_SILENT_EXECUTE, "bu %s", CodeExpr);
}
}
HMENU
DOCWIN_DATA::GetContextMenu(void)
{
return s_ContextMenu;
}
void
DOCWIN_DATA::OnContextMenuSelection(UINT Item)
{
CHARRANGE Sel;
int Line;
TCHAR SelText[256];
Item -= DOCWIN_CONTEXT_ID_BASE;
switch(Item)
{
case DOCWIN_TBB_SET_IP:
SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&Sel);
Line = (int)
SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0, Sel.cpMin);
PrintStringCommand(UIC_SET_IP, "r$ip = @@masm(`%s:%d+`)",
m_SymFile, Line + 1);
break;
case DOCWIN_TBB_INVOKE_EDITOR:
SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&Sel);
Line = (int)
SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0, Sel.cpMin);
RunEditorCommand(g_EditorInvokeCommand, m_FoundFile, Line);
break;
case DOCWIN_TBB_COPY:
SendMessage(m_hwndChild, WM_COPY, 0, 0);
break;
case DOCWIN_TBB_EVAL:
SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&Sel);
if (Sel.cpMax > Sel.cpMin)
{
if (!RicheditGetSelectionText(m_hwndChild, SelText, DIMA(SelText)))
{
break;
}
}
else if (!RicheditGetSourceToken(m_hwndChild, SelText, DIMA(SelText),
&Sel))
{
break;
}
PrintStringCommand(UIC_EXECUTE, "?? %s", SelText);
break;
case DOCWIN_TBB_DT:
SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&Sel);
if (Sel.cpMax > Sel.cpMin)
{
if (!RicheditGetSelectionText(m_hwndChild, SelText, DIMA(SelText)))
{
break;
}
}
else if (!RicheditGetSourceToken(m_hwndChild, SelText, DIMA(SelText),
&Sel))
{
break;
}
PrintStringCommand(UIC_EXECUTE, "dt %s", SelText);
break;
case DOCWIN_TBB_VIEW_IP:
SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&Sel);
Line = (int)
SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0, Sel.cpMin);
PrintStringCommand(UIC_DISPLAY_CODE_EXPR, "@@masm(`%s:%d+`)",
m_SymFile, Line + 1);
break;
}
}
BOOL
DOCWIN_DATA::OnCreate(void)
{
if (s_ContextMenu == NULL &&
g_EditorInvokeCommand)
{
s_ContextMenu = CreateContextMenuFromToolbarButtons
(NUM_DOCWIN_MENU_BUTTONS, g_DocWinTbButtons,
DOCWIN_CONTEXT_ID_BASE);
if (s_ContextMenu == NULL)
{
return FALSE;
}
}
if (!EDITWIN_DATA::OnCreate())
{
return FALSE;
}
SendMessage(m_hwndChild, EM_SETEDITSTYLE,
SES_XLTCRCRLFTOCR, SES_XLTCRCRLFTOCR);
SendMessage(m_hwndChild, EM_SETEVENTMASK,
0, ENM_SELCHANGE | ENM_KEYEVENTS | ENM_MOUSEEVENTS);
SendMessage(m_hwndChild, EM_SETTABSTOPS, 1, (LPARAM)&g_TabWidth);
return TRUE;
}
LRESULT
DOCWIN_DATA::OnNotify(WPARAM Wpm, LPARAM Lpm)
{
NMHDR* Hdr = (NMHDR*)Lpm;
if (Hdr->code == EN_SELCHANGE)
{
SELCHANGE* SelChange = (SELCHANGE*)Lpm;
int Line = (int)
SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0,
SelChange->chrg.cpMin);
LRESULT LineFirst =
SendMessage(m_hwndChild, EM_LINEINDEX, Line, 0);
SetLineColumn_StatusBar(Line + 1,
(int)(SelChange->chrg.cpMin - LineFirst) + 1);
return 0;
}
else if (Hdr->code == EN_MSGFILTER)
{
MSGFILTER* Filter = (MSGFILTER*)Lpm;
char Token[256];
CHARRANGE TokenRange;
if (Filter->msg == WM_LBUTTONDBLCLK &&
RicheditGetSourceToken(m_hwndChild, Token, DIMA(Token),
&TokenRange))
{
SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&TokenRange);
return 1;
}
}
return EDITWIN_DATA::OnNotify(Wpm, Lpm);
}
void
DOCWIN_DATA::OnUpdate(
UpdateType Type
)
{
if (Type == UPDATE_BP ||
Type == UPDATE_BUFFER ||
Type == UPDATE_END_SESSION)
{
UpdateBpMarks();
}
else if (Type == UPDATE_START_SESSION ||
Type == UPDATE_REFRESH_MODULES)
{
// If there's already a message box open we don't
// want to put up a new one. This may mean we
// miss a source file change but it should be relatively
// uncommon. If it's a problem we could start up a timer
// to repost the update later.
if (g_nBoxCount == 0 &&
m_FoundFile[0] &&
CheckForFileChanges(m_FoundFile, &m_LastWriteTime) == IDYES)
{
char Found[MAX_SOURCE_PATH], Sym[MAX_SOURCE_PATH];
char PathComp[MAX_SOURCE_PATH];
// Save away filenames since they're copied over
// on a successful load.
strcpy(Found, m_FoundFile);
strcpy(Sym, m_SymFileBuffer);
strcpy(PathComp, m_PathComponent);
if (!LoadFile(Found, Sym, PathComp))
{
PostMessage(g_hwndMDIClient, WM_MDIDESTROY, (WPARAM)m_Win, 0);
}
}
}
}
ULONG
DOCWIN_DATA::GetWorkspaceSize(void)
{
ULONG Len = EDITWIN_DATA::GetWorkspaceSize();
Len += _tcslen(m_FoundFile) + 1;
Len += _tcslen(m_SymFileBuffer) + 1;
Len += _tcslen(m_PathComponent) + 1;
Len += sizeof(LONG);
return Len;
}
PUCHAR
DOCWIN_DATA::SetWorkspace(PUCHAR Data)
{
PTSTR Str = (PTSTR)EDITWIN_DATA::SetWorkspace(Data);
_tcscpy(Str, m_FoundFile);
Str += _tcslen(m_FoundFile) + 1;
_tcscpy(Str, m_SymFileBuffer);
Str += _tcslen(m_SymFileBuffer) + 1;
_tcscpy(Str, m_PathComponent);
Str += _tcslen(m_PathComponent) + 1;
CHARRANGE Sel;
SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&Sel);
*(LONG UNALIGNED *)Str = Sel.cpMin;
Str += sizeof(Sel.cpMin);
return (PUCHAR)Str;
}
PUCHAR
DOCWIN_DATA::ApplyWorkspace1(PUCHAR Data, PUCHAR End)
{
PTSTR Found = (PTSTR)EDITWIN_DATA::ApplyWorkspace1(Data, End);
PTSTR Sym = Found + _tcslen(Found) + 1;
PTSTR SymEnd = Sym + _tcslen(Sym) + 1;
PTSTR PathComp = SymEnd;
if ((PUCHAR)PathComp >= End || !PathComp[0])
{
PathComp = NULL;
}
if ((PUCHAR)SymEnd >= End)
{
Data = (PUCHAR)SymEnd;
}
else
{
Data = (PUCHAR)(SymEnd + _tcslen(SymEnd) + 1);
}
if (Found[0])
{
if (FindDocWindowByFileName(Found, NULL, NULL) ||
!LoadFile(Found, Sym[0] ? Sym : NULL, PathComp))
{
PostMessage(g_hwndMDIClient, WM_MDIDESTROY, (WPARAM)m_Win, 0);
}
}
if (Data < End)
{
CHARRANGE Sel;
Sel.cpMin = *(LONG UNALIGNED *)Data;
Sel.cpMax = Sel.cpMin;
SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&Sel);
SendMessage(m_hwndChild, EM_SCROLLCARET, 0, 0);
Data += sizeof(Sel.cpMin);
}
return Data;
}
void
DOCWIN_DATA::UpdateBpMarks(void)
{
if (m_TextLines == 0 ||
g_BpBuffer->UiLockForRead() != S_OK)
{
return;
}
SendMessage(m_hwndChild, WM_SETREDRAW, FALSE, 0);
// Remove existing BP highlights.
RemoveAllHighlights(EHL_ANY_BP);
//
// Highlight every line that matches a breakpoint.
//
BpBufferData* BpData = (BpBufferData*)g_BpBuffer->GetDataBuffer();
ULONG i;
for (i = 0; i < g_BpCount; i++)
{
if (BpData[i].FileOffset)
{
PSTR FileSpace;
ULONG Line;
PSTR FileStop, MatchStop;
ULONG HlFlags;
FileSpace = (PSTR)g_BpBuffer->GetDataBuffer() +
BpData[i].FileOffset;
// Adjust to zero-based.
Line = *(ULONG UNALIGNED *)FileSpace - 1;
FileSpace += sizeof(Line);
// If this document's file matches some suffix
// of the breakpoint's file at the path component
// level then do the highlight. This can result in
// extra highlights for multiple files with the same
// name but in different directories. That's a rare
// enough problem to wait for somebody to complain
// before trying to hack some better check up.
if (SymMatchFileName(FileSpace, (PSTR)m_SymFile,
&FileStop, &MatchStop) ||
*MatchStop == '\\' ||
*MatchStop == '/' ||
*MatchStop == ':')
{
if (BpData[i].Flags & DEBUG_BREAKPOINT_ENABLED)
{
HlFlags = EHL_ENABLED_BP;
}
else
{
HlFlags = EHL_DISABLED_BP;
}
EDIT_HIGHLIGHT* Hl = AddHighlight(Line, HlFlags);
if (Hl != NULL)
{
Hl->Data = BpData[i].Id;
}
}
}
}
UnlockStateBuffer(g_BpBuffer);
SendMessage(m_hwndChild, WM_SETREDRAW, TRUE, 0);
InvalidateRect(m_hwndChild, NULL, TRUE);
}
DWORD
CALLBACK
EditStreamCallback(
DWORD_PTR dwFileHandle, // application-defined value
LPBYTE pbBuff, // data buffer
LONG cb, // number of bytes to read or write
LONG *pcb // number of bytes transferred
)
{
HRESULT Status;
PathFile* File = (PathFile*)dwFileHandle;
if ((Status = File->Read(pbBuff, cb, (PDWORD)pcb)) != S_OK)
{
return Status;
}
// Edit out page-break characters (^L's) as richedit
// gives them their own line which throws off line numbers.
while (cb-- > 0)
{
if (*pbBuff == '\f')
{
*pbBuff = ' ';
}
pbBuff++;
}
return 0; // No error
}
BOOL
DOCWIN_DATA::LoadFile(
PCTSTR pszFoundFile,
PCTSTR pszSymFile,
PCTSTR pszPathComponent
)
/*++
Returns
TRUE - Success, file opened and loaded
FALSE - Failure, file not loaded
--*/
{
Assert(pszFoundFile);
BOOL bRet = TRUE;
HCURSOR hcursor = NULL;
EDITSTREAM editstr = {0};
PathFile *File = NULL;
if ((OpenPathFile(pszPathComponent, pszFoundFile, 0, &File)) != S_OK)
{
ErrorBox(NULL, 0, ERR_File_Open, pszFoundFile);
bRet = FALSE;
goto exit;
}
// Store last write time to check for file changes.
if (File->GetLastWriteTime(&m_LastWriteTime) != S_OK)
{
ZeroMemory(&m_LastWriteTime, sizeof(m_LastWriteTime));
}
// Set the Hour glass cursor
hcursor = SetCursor( LoadCursor(NULL, IDC_WAIT) );
// Select all of the text so that it will be replaced
SendMessage(m_hwndChild, EM_SETSEL, 0, -1);
// Put the text into the window
editstr.dwCookie = (DWORD_PTR)File;
editstr.pfnCallback = EditStreamCallback;
SendMessage(m_hwndChild,
EM_STREAMIN,
SF_TEXT,
(LPARAM) &editstr
);
RicheditUpdateColors(m_hwndChild,
g_Colors[COL_PLAIN_TEXT].Color, TRUE,
g_Colors[COL_PLAIN].Color, TRUE);
// Restore cursor
SetCursor(hcursor);
_tcsncpy(m_FoundFile, pszFoundFile, _tsizeof(m_FoundFile) - 1 );
m_FoundFile[ _tsizeof(m_FoundFile) - 1 ] = 0;
if (pszSymFile != NULL && pszSymFile[0])
{
_tcsncpy(m_SymFileBuffer, pszSymFile, _tsizeof(m_SymFileBuffer) - 1 );
m_SymFileBuffer[ _tsizeof(m_SymFileBuffer) - 1 ] = 0;
m_SymFile = m_SymFileBuffer;
}
else
{
// No symbol file information so just use the found filename.
m_SymFileBuffer[0] = 0;
m_SymFile = strrchr(m_FoundFile, '\\');
if (m_SymFile == NULL)
{
m_SymFile = strrchr(m_FoundFile, '/');
if (m_SymFile == NULL)
{
m_SymFile = strrchr(m_FoundFile, ':');
if (m_SymFile == NULL)
{
m_SymFile = m_FoundFile - 1;
}
}
}
m_SymFile++;
}
if (pszPathComponent)
{
_tcsncpy(m_PathComponent, pszPathComponent,
_tsizeof(m_PathComponent) - 1);
m_PathComponent[_tsizeof(m_PathComponent) - 1] = 0;
}
else
{
m_PathComponent[0] = 0;
}
SetWindowText(m_Win, m_FoundFile);
if (SendMessage(m_hwndChild, WM_GETTEXTLENGTH, 0, 0) == 0)
{
m_TextLines = 0;
}
else
{
m_TextLines = (ULONG)SendMessage(m_hwndChild, EM_GETLINECOUNT, 0, 0);
}
if (g_LineMarkers)
{
// Insert marker space before every line.
for (ULONG i = 0; i < m_TextLines; i++)
{
CHARRANGE Ins;
Ins.cpMin = (LONG)SendMessage(m_hwndChild, EM_LINEINDEX, i, 0);
Ins.cpMax = Ins.cpMin;
SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&Ins);
SendMessage(m_hwndChild, EM_REPLACESEL, FALSE, (LPARAM)" ");
}
}
// Request that the engine update the line map for the file.
UiRequestRead();
exit:
delete File;
return bRet;
}
BOOL
SameFileName(PCSTR Name1, PCSTR Name2)
{
while (*Name1)
{
if (!(((*Name1 == '\\' || *Name1 == '/') &&
(*Name2 == '\\' || *Name2 == '/')) ||
toupper(*Name1) == toupper(*Name2)))
{
return FALSE;
}
Name1++;
Name2++;
}
return *Name2 == 0;
}
BOOL
FindDocWindowByFileName(
IN PCTSTR pszFile,
OPTIONAL HWND *phwnd,
OPTIONAL PDOCWIN_DATA *ppDocWinData
)
/*++
Returns
TRUE - If the window is currently open.
FALSE - Not currently open.
--*/
{
Assert(pszFile);
PLIST_ENTRY Entry;
PDOCWIN_DATA pTmp;
Entry = g_ActiveWin.Flink;
while (Entry != &g_ActiveWin)
{
pTmp = (PDOCWIN_DATA)ACTIVE_WIN_ENTRY(Entry);
if ( pTmp->m_enumType == DOC_WINDOW &&
SameFileName(pTmp->m_FoundFile, pszFile) )
{
if (ppDocWinData)
{
*ppDocWinData = pTmp;
}
if (phwnd)
{
*phwnd = pTmp->m_Win;
}
return TRUE;
}
Entry = Entry->Flink;
}
return FALSE;
}
BOOL
OpenOrActivateFile(PCSTR FoundFile, PCSTR SymFile, PCSTR PathComponent,
ULONG Line, BOOL Activate, BOOL UserActivated)
{
HWND hwndDoc = NULL;
PDOCWIN_DATA pDoc;
BOOL Activated = FALSE;
if ( FindDocWindowByFileName( FoundFile, &hwndDoc, &pDoc) )
{
if (Activate)
{
// Found it. Now activate it.
if (IsIconic(hwndDoc))
{
ShowWindow(hwndDoc, SW_RESTORE);
}
ActivateMDIChild(hwndDoc, UserActivated);
Activated = TRUE;
}
}
else
{
HWND WinTop, WinUnder;
WinTop = MDIGetActive(g_hwndMDIClient, NULL);
if (WinTop)
{
WinUnder = GetNextWindow(WinTop, GW_HWNDNEXT);
}
else
{
WinUnder = NULL;
}
hwndDoc = NewDoc_CreateWindow(g_hwndMDIClient);
if (hwndDoc == NULL)
{
return FALSE;
}
pDoc = GetDocWinData(hwndDoc);
Assert(pDoc);
if (!pDoc->LoadFile(FoundFile, SymFile, PathComponent))
{
DestroyWindow(pDoc->m_Win);
return FALSE;
}
if (!UserActivated && WinTop)
{
// If this isn't a user-provoked activation we don't
// want the window to obscure the user's current window.
// Reorder the current windows appropriately.
ReorderChildren(WinUnder, WinTop, pDoc->m_Win,
UserActivated);
}
Activated = TRUE;
}
// Success. Now highlight the line.
pDoc->SetCurrentLineHighlight(Line);
return Activated;
}
void
UpdateCodeDisplay(
ULONG64 Ip,
PCSTR FoundFile,
PCSTR SymFile,
PCSTR PathComponent,
ULONG Line,
BOOL UserActivated
)
{
// Update the disassembly window if there's one
// active or there's no source information.
BOOL Activated = FALSE;
HWND hwndDisasm = GetDisasmHwnd();
if (hwndDisasm == NULL && FoundFile == NULL &&
(g_WinOptions & WOPT_AUTO_DISASM))
{
// No disassembly window around and no source so create one.
hwndDisasm = NewDisasm_CreateWindow(g_hwndMDIClient);
}
if (hwndDisasm != NULL)
{
PDISASMWIN_DATA pDis = GetDisasmWinData(hwndDisasm);
Assert(pDis);
pDis->SetCurInstr(Ip);
}
if (FoundFile != NULL)
{
//
// We now know the file name and line number. Either
// it's open or we open it.
//
Activated = OpenOrActivateFile(FoundFile, SymFile, PathComponent, Line,
GetSrcMode_StatusBar() ||
g_DisasmActivateSource,
UserActivated);
RunEditorCommand(g_EditorUpdateCommand, FoundFile, Line);
}
else
{
// No source file was found so make sure no
// doc windows have a highlight.
EDITWIN_DATA::RemoveActiveWinHighlights(1 << DOC_WINDOW,
EHL_CURRENT_LINE);
}
if ((!Activated || !GetSrcMode_StatusBar()) && hwndDisasm != NULL)
{
// No window has been activated yet so fall back
// on activating the disassembly window.
ActivateMDIChild(hwndDisasm, UserActivated);
}
}
void
SetTabWidth(ULONG TabWidth)
{
PLIST_ENTRY Entry;
PDOCWIN_DATA DocData;
g_TabWidth = TabWidth;
if (g_Workspace != NULL)
{
g_Workspace->SetUlong(WSP_GLOBAL_TAB_WIDTH, TabWidth);
}
Entry = g_ActiveWin.Flink;
while (Entry != &g_ActiveWin)
{
DocData = (PDOCWIN_DATA)ACTIVE_WIN_ENTRY(Entry);
if (DocData->m_enumType == DOC_WINDOW)
{
SendMessage(DocData->m_hwndChild, EM_SETTABSTOPS,
1, (LPARAM)&g_TabWidth);
}
Entry = Entry->Flink;
}
}
void
GetEditorCommandDefaults(void)
{
PSTR Env;
HKEY Key;
// As a convenience for windiff users pick up the
// windiff editor registry setting.
if (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windiff",
0, KEY_READ, &Key) == ERROR_SUCCESS)
{
DWORD Type;
DWORD Size;
Size = sizeof(g_EditorInvokeCommand);
if (RegQueryValueExA(Key, "Editor", NULL, &Type,
(LPBYTE)g_EditorInvokeCommand,
&Size) != ERROR_SUCCESS ||
Type != REG_SZ)
{
strcpy(g_EditorInvokeCommand, INVOKE_DEFAULT);
}
RegCloseKey(Key);
}
Env = getenv("WINDBG_INVOKE_EDITOR");
if (Env)
{
CopyString(g_EditorInvokeCommand, Env, DIMA(g_EditorInvokeCommand));
}
Env = getenv("WINDBG_UPDATE_EDITOR");
if (Env)
{
CopyString(g_EditorUpdateCommand, Env, DIMA(g_EditorInvokeCommand));
}
}