windows-nt/Source/XPSP1/NT/sdktools/debuggers/windbg/util.cpp

1632 lines
40 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1999-2001 Microsoft Corporation
Module Name:
util.cpp
--*/
#include "precomp.hxx"
#pragma hdrstop
//Current Help Id for Open, Merge, Save and Open project dialog box
WORD g_CurHelpId;
// Number of dialog/message boxes currently open
int g_nBoxCount;
BOOL g_fNoPopups;
HWND
MDIGetActive(
HWND hwndParent,
BOOL *lpbMaximized
)
/*++
Routine Description:
Create the command window.
Arguments:
hwndParent - The parent window to the command window. In an MDI document,
this is usually the handle to the MDI client window: g_hwndMDIClient
Return Value:
The return value is the handle to the active MDI child window.
NULL if no MDI window has been created.
--*/
{
Assert(IsWindow(hwndParent));
return (HWND)SendMessage(hwndParent,
WM_MDIGETACTIVE,
0,
(LPARAM)lpbMaximized
);
}
/*** hGetBoxParent
**
** Synopsis:
** hwnd = hGetBoxParent()
**
** Entry:
** none
**
** Returns:
**
** Description:
** Gets a suitable parent window handle for an
** invocation of a message or dialog box.
** Helper function to util.c functions so declared
** near.
**
*/
HWND
hGetBoxParent()
{
HWND hCurWnd;
int i = 0;
hCurWnd = GetFocus();
if (hCurWnd)
{
while (GetWindowLong(hCurWnd, GWL_STYLE) & WS_CHILD)
{
hCurWnd = GetParent(hCurWnd);
Dbg((++i < 100));
}
}
else
{
hCurWnd = g_hwndFrame;
}
return hCurWnd;
}
/****************************************************************************
FUNCTION: MsgBox
PURPOSE: General purpose message box routine which takes
a pointer to the message text. Provides
program title as caption.
****************************************************************************/
int
MsgBox(
HWND hwndParent,
PTSTR szText,
UINT wType
)
/*++
Routine Description:
Generial purpose message box routine which takes a pointer to a message
text and prvoides the program title for the caption of the message box.
Arguments:
hwndParament - Supplies the parent window handle for the message box
szText - Supplies a pointer to the message box text.
wType - Supplies the message box type (to specify buttons)
Return Value:
Returns the message box return code
--*/
{
int MsgBoxRet = IDOK;
if (g_fNoPopups)
{
//
// log the string to the command win in case testing
// or when the remote server is running
//
CmdLogFmt (_T("%s\r\n"), szText);
}
else
{
g_nBoxCount++;
MsgBoxRet = MessageBox(hwndParent, szText,
g_MainTitleText, wType);
g_nBoxCount--;
}
return MsgBoxRet;
} /* MsgBox() */
/*** ErrorBox
**
** Returns:
** FALSE
**
** Description:
** Display an error message box with an "Error" title, an OK
** button and a Exclamation Icon. First parameter is a
** reference string in the ressource file. The string
** can contain printf formatting chars, the arguments
** follow from the second parameter onwards.
**
*/
BOOL
ErrorBox(
HWND hwnd,
UINT type,
int wErrorFormat,
...
)
{
TCHAR szErrorFormat[MAX_MSG_TXT];
TCHAR szErrorText[MAX_VAR_MSG_TXT]; // size is as big as considered necessary
va_list vargs;
// load format string from resource file
Dbg(LoadString(g_hInst, wErrorFormat, (PTSTR)szErrorFormat, MAX_MSG_TXT));
va_start(vargs, wErrorFormat);
_vstprintf(szErrorText, szErrorFormat, vargs);
va_end(vargs);
if (hwnd == NULL)
{
hwnd = g_hwndFrame;
}
if (type == 0)
{
type = MB_TASKMODAL;
}
MsgBox(g_hwndFrame, (PTSTR)szErrorText, type | MB_OK | MB_ICONINFORMATION);
return FALSE; //Keep it always FALSE please
}
/*** InformationBox
**
** Description:
** Display an information message box with an "Information"
** title, an OK button and an Information Icon.
**
*/
void
InformationBox(
WORD wDescript
...
)
{
TCHAR szFormat[MAX_MSG_TXT];
TCHAR szText[MAX_VAR_MSG_TXT]; // size is as big as considered necessary
va_list vargs;
// load format string from resource file
Dbg(LoadString(g_hInst, wDescript, (PTSTR)szFormat, MAX_MSG_TXT));
// set up szText from passed parameters
va_start(vargs, wDescript);
_vstprintf(szText, szFormat, vargs);
va_end(vargs);
MsgBox(g_hwndFrame, (PTSTR)szText, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
return;
}
/*** QuestionBox
**
** Synopsis:
** int = QuestionBox(wCaptionId, wMsgFormat, wType, ...)
**
** Entry:
**
** Returns:
** The result of the message box call
**
** Description:
** Display an query box with combination of YES, NO and
** CANCEL buttons and a question mark Icon.
** See ErrorBox for discussion.
**
*/
int
CDECL
QuestionBox(
WORD wMsgFormat,
UINT wType,
...
)
{
TCHAR szMsgFormat[MAX_MSG_TXT];
TCHAR szMsgText[MAX_VAR_MSG_TXT];
va_list vargs;
//Load format string from resource file
Dbg(LoadString(g_hInst, wMsgFormat, (PTSTR)szMsgFormat, MAX_MSG_TXT));
//Set up szMsgText from passed parameters
va_start(vargs, wType);
_vstprintf(szMsgText, szMsgFormat, vargs);
va_end(vargs);
return MsgBox(g_hwndFrame, szMsgText,
wType | MB_ICONEXCLAMATION | MB_TASKMODAL);
} /* QuestionBox() */
/****************************************************************************
FUNCTION: QuestionBox2
PURPOSE: Display an query box with combination of YES, NO and
CANCEL buttons and a question mark Icon. The type and
the parent window are adjustable.
RETURNS: MessageBox result
****************************************************************************/
int
CDECL
QuestionBox2(
HWND hwnd,
WORD wMsgFormat,
UINT wType,
...
)
{
TCHAR szMsgFormat[MAX_MSG_TXT];
TCHAR szMsgText[MAX_VAR_MSG_TXT];
va_list vargs;
//Load format string from resource file
Dbg(LoadString(g_hInst, wMsgFormat, (PTSTR)szMsgFormat, MAX_MSG_TXT));
//Set up szMsgText from passed parameters
va_start(vargs, wType);
_vstprintf(szMsgText, szMsgFormat, vargs);
va_end(vargs);
return MsgBox(hwnd, szMsgText, wType | MB_ICONEXCLAMATION);
} /* QuestionBox2() */
/*** ShowAssert
**
** Synopsis:
** void = ShowAssert(szCond, iLine, szFile)
**
** Entry:
** szCond - tokenized form of the failed condition
** iLine - Line number for the assertion
** szFile - File for the assertion
**
** Returns:
** void
**
** Description:
** Prepare and display a Message Box with szCondition, iLine and
** szFile as fields.
**
*/
void
ShowAssert(
PTSTR condition,
UINT line,
PTSTR file
)
{
TCHAR text[MAX_VAR_MSG_TXT];
//Build line, show assertion and exit program
_stprintf(text, _T("- Line:%u, File:%Fs, Condition:%Fs"),
(WPARAM) line, file, condition);
TCHAR szBuffer[_MAX_PATH];
PTSTR pszBuffer;
PTSTR szAssertFile = _T("assert.wbg");
HANDLE hFile = NULL;
hFile = CreateFile(szAssertFile,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (INVALID_HANDLE_VALUE != hFile)
{
// Write the text out to the file
DWORD dwBytesWritten = 0;
Assert(WriteFile(hFile, text, _tcslen(text), &dwBytesWritten, NULL));
Assert(_tcslen(text) == dwBytesWritten);
CloseHandle(hFile);
}
int Action =
MessageBox(GetDesktopWindow(), text, "Assertion Failure",
MB_ABORTRETRYIGNORE);
if (Action == IDABORT)
{
exit(3);
}
else if (Action == IDRETRY)
{
DebugBreak();
}
} // ShowAssert()
/*** StartDialog
**
** Synopsis:
** int = StartDialog(rcDlgNb, dlgProc, lParam)
**
** Entry:
** rcDlgNb - Resource number of dialog to be openned
** dlgProc - Filter procedure for the dialog
** lParam - Data passed into the dlg proc via LPARAM
**
** Returns:
** Result of the dialog box call
**
** Description:
** Loads and execute the dialog box 'rcDlgNb' (resource
** file string number) associated with the dialog
** function 'dlgProc'
**
*/
int
StartDialog(
int rcDlgNb,
DLGPROC dlgProc,
LPARAM lParam
)
{
LRESULT result;
//
//Execute Dialog Box
//
g_nBoxCount++;
result = DialogBoxParam(g_hInst,
MAKEINTRESOURCE(rcDlgNb),
hGetBoxParent(),
dlgProc,
lParam
);
Assert(result != (LRESULT)-1);
g_nBoxCount--;
return (int)result;
}
void
ProcessNonDlgMessage(LPMSG Msg)
{
#if 0
{
DebugPrint("NonDlg msg %X for %p, args %X %X\n",
Msg->message, Msg->hwnd, Msg->wParam, Msg->lParam);
}
#endif
// If a keyboard message is for the MDI , let the MDI client
// take care of it. Otherwise, check to see if it's a normal
// accelerator key (like F3 = find next). Otherwise, just handle
// the message as usual.
if (!TranslateMDISysAccel(g_hwndMDIClient, Msg) &&
!TranslateAccelerator(g_hwndFrame, g_hMainAccTable, Msg))
{
//
// If this is a right-button-down over a child window,
// automatically activate the window's contex menu.
//
if (Msg->message == WM_RBUTTONDOWN &&
IsChild(g_hwndMDIClient, Msg->hwnd))
{
HMENU Menu;
PCOMMONWIN_DATA CmnWin;
POINT ScreenPt;
POINT Pt = {LOWORD(Msg->lParam), HIWORD(Msg->lParam)};
ClientToScreen(Msg->hwnd, &Pt);
ScreenPt = Pt;
ScreenToClient(g_hwndMDIClient, &Pt);
HWND Win = ChildWindowFromPointEx(g_hwndMDIClient, Pt,
CWP_SKIPINVISIBLE);
if (Win != NULL &&
(CmnWin = GetCommonWinData(Win)) != NULL &&
(Menu = CmnWin->GetContextMenu()) != NULL)
{
UINT Item = TrackPopupMenu(Menu, TPM_LEFTALIGN | TPM_TOPALIGN |
TPM_NONOTIFY | TPM_RETURNCMD |
TPM_RIGHTBUTTON,
ScreenPt.x, ScreenPt.y,
0, Msg->hwnd, NULL);
if (Item)
{
CmnWin->OnContextMenuSelection(Item);
}
return;
}
}
TranslateMessage(Msg);
DispatchMessage(Msg);
}
}
void
ProcessPendingMessages(void)
{
MSG Msg;
// Process all available messages.
while (PeekMessage(&Msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!GetMessage(&Msg, NULL, 0, 0))
{
g_Exit = TRUE;
break;
}
if (g_FindDialog == NULL ||
!IsDialogMessage(g_FindDialog, &Msg))
{
ProcessNonDlgMessage(&Msg);
}
}
}
/****************************************************************************
FUNCTION: InfoBox
PURPOSE: Opens a Dialog box with a title and accepting
a printf style for text. It's for DEBUGGING USE ONLY
****************************************************************************/
int
InfoBox(
PTSTR text,
...
)
{
TCHAR buffer[MAX_MSG_TXT];
va_list vargs;
va_start(vargs, text);
_vstprintf(buffer, text, vargs);
va_end(vargs);
return MsgBox(GetActiveWindow(), buffer, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
}
void
ExitDebugger(PDEBUG_CLIENT Client, ULONG Code)
{
if (Client != NULL && !g_RemoteClient)
{
Client->EndSession(DEBUG_END_PASSIVE);
// Force servers to get cleaned up.
Client->EndSession(DEBUG_END_REENTRANT);
}
ExitProcess(Code);
}
// XXX drewb - Is this functionality present in other utilities?
// FatalErrorBox is close. Probably can combine something here.
void
ErrorExit(PDEBUG_CLIENT Client, PCSTR Format, ...)
{
char Message[1024];
va_list Args;
va_start(Args, Format);
_vsnprintf(Message, sizeof(Message), Format, Args);
va_end(Args);
// XXX drewb - Could put up message box.
OutputDebugString(Message);
ExitDebugger(Client, E_FAIL);
}
#define MAX_FORMAT_STRINGS 8
LPSTR
FormatAddr64(
ULONG64 addr
)
/*++
Routine Description:
Format a 64 bit address, showing the high bits or not
according to various flags.
An array of static string buffers is used, returning a different
buffer for each successive call so that it may be used multiple
times in the same printf.
Arguments:
addr - Supplies the value to format
Return Value:
A pointer to the string buffer containing the formatted number
--*/
{
static CHAR strings[MAX_FORMAT_STRINGS][18];
static int next = 0;
LPSTR string;
string = strings[next];
++next;
if (next >= MAX_FORMAT_STRINGS) {
next = 0;
}
if (g_Ptr64) {
sprintf(string, "%08x`%08x", (ULONG)(addr>>32), (ULONG)addr);
} else {
sprintf(string, "%08x", (ULONG)addr);
}
return string;
}
static BOOL FAddToSearchPath = FALSE;
static BOOL FAddToRootMap = FALSE;
/*
** AppendFilter
**
** Description:
** Append a filter to an existing filters string.
**
*/
BOOL
AppendFilter(
WORD filterTextId,
int filterExtId,
PTSTR filterString,
int *len,
int maxLen
)
{
int size;
TCHAR Tmp[MAX_MSG_TXT];
//
// Append filter text
//
Dbg(LoadString(g_hInst, filterTextId, Tmp, MAX_MSG_TXT));
size = _tcslen(Tmp) + 1;
if (*len + size > maxLen)
{
return FALSE;
}
memmove(filterString + *len, Tmp, size);
*len += size;
//
// Append filter extension
//
Dbg(LoadString(g_hInst, filterExtId, Tmp, MAX_MSG_TXT));
size = _tcslen(Tmp) + 1;
if (*len + size > maxLen)
{
return FALSE;
}
memmove(filterString + *len, Tmp, size);
*len += size;
return TRUE;
}
/*
** InitFilterString
**
** Description:
** Initialize file filters for file dialog boxes.
*/
void
InitFilterString(
WORD titleId,
PTSTR filter,
int maxLen
)
{
int len = 0;
switch (titleId) {
case DLG_Browse_CrashDump_Title:
AppendFilter(TYP_File_DUMP, DEF_Ext_DUMP, filter, &len, maxLen);
break;
case DLG_Browse_Executable_Title:
AppendFilter(TYP_File_EXE, DEF_Ext_EXE, filter, &len, maxLen);
break;
case DLG_Browse_LogFile_Title:
AppendFilter(TYP_File_LOG, DEF_Ext_LOG, filter, &len, maxLen);
break;
case DLG_Open_Filebox_Title:
case DLG_Browse_Filebox_Title:
AppendFilter(TYP_File_SOURCE, DEF_Ext_SOURCE, filter, &len, maxLen);
AppendFilter(TYP_File_INCLUDE, DEF_Ext_INCLUDE, filter, &len, maxLen);
AppendFilter(TYP_File_ASMSRC, DEF_Ext_ASMSRC, filter, &len, maxLen);
AppendFilter(TYP_File_INC, DEF_Ext_INC, filter, &len, maxLen);
AppendFilter(TYP_File_RC, DEF_Ext_RC, filter, &len, maxLen);
AppendFilter(TYP_File_DLG, DEF_Ext_DLG, filter, &len, maxLen);
AppendFilter(TYP_File_DEF, DEF_Ext_DEF, filter, &len, maxLen);
AppendFilter(TYP_File_MAK, DEF_Ext_MAK, filter, &len, maxLen);
break ;
case DLG_Browse_DbugDll_Title:
AppendFilter(TYP_File_DLL, DEF_Ext_DLL, filter, &len, maxLen);
break;
default:
Assert(FALSE);
break;
}
AppendFilter(TYP_File_ALL, DEF_Ext_ALL, filter, &len, maxLen);
filter[len] = _T('\0');
}
BOOL
StartFileDlg(
HWND hwnd,
int titleId,
int defExtId,
int helpId,
int templateId,
PTSTR InitialDir,
PTSTR fileName,
DWORD* pFlags,
LPOFNHOOKPROC lpfnHook
)
/*++
Routine Description:
This function is used by windbg to open the set of common file handling
dialog boxes.
Arguments:
hwnd - Supplies the wnd to hook the dialog box to
titleId - Supplies the string resource of the title
defExtId - Supplies The default extension resource string
helpId - Supplies the help number for the dialog box
templateId - Supplies the dialog resource number if non-zero
fileName - Supplies the default file name
pFiles - Supplies a pointer to flags
lpfnHook - Supplies the address of a hook procedure for the dialog
Return Value:
The result of the dialog box call (usually TRUE for OK and FALSE for
cancel)
--*/
{
#define filtersMaxSize 350
OPENFILENAME_NT4 OpenFileName = {0};
TCHAR title[MAX_MSG_TXT];
TCHAR defExt[MAX_MSG_TXT];
BOOL result;
TCHAR filters[filtersMaxSize];
LPOFNHOOKPROC lpDlgHook = NULL;
HCURSOR hSaveCursor;
TCHAR files[_MAX_PATH + 8];
TCHAR szExt[_MAX_EXT + 8];
TCHAR szBase[_MAX_PATH + 8];
int indx;
TCHAR ch;
TCHAR fname[_MAX_FNAME];
TCHAR ext[_MAX_EXT];
PTSTR LocalInitialDir = NULL;
*pFlags |= (OFN_EXPLORER | OFN_NOCHANGEDIR);
if (InitialDir == NULL || !InitialDir[0])
{
DWORD retval = GetCurrentDirectory(NULL, NULL);
InitialDir = (PTSTR)calloc(retval, sizeof(TCHAR) );
if (InitialDir == NULL)
{
return FALSE;
}
GetCurrentDirectory(retval, InitialDir);
LocalInitialDir = InitialDir;
}
if (DLG_Browse_Filebox_Title == titleId)
{
_tsplitpath( fileName, NULL, NULL, fname, ext );
_tmakepath( files, NULL, NULL, fname, ext );
}
else
{
_tcscpy(files, fileName);
}
//
// Set the Hour glass cursor
//
hSaveCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
InitFilterString((WORD)titleId, (PTSTR)filters, (int)filtersMaxSize);
Dbg(LoadString(g_hInst, titleId, (PTSTR)title, MAX_MSG_TXT));
Dbg(LoadString(g_hInst, defExtId, (PTSTR)defExt, MAX_MSG_TXT));
if (templateId)
{
//
// Build dialog box Name
//
*pFlags |= OFN_ENABLETEMPLATE;
OpenFileName.lpTemplateName = MAKEINTRESOURCE(templateId);
}
else
{
*pFlags |= OFN_EXPLORER;
}
//
// Make instance for _T('dlgProc')
//
if (lpfnHook)
{
lpDlgHook = lpfnHook;
*pFlags |= OFN_ENABLEHOOK;
}
g_CurHelpId = (WORD) helpId;
OpenFileName.lStructSize = sizeof(OpenFileName);
OpenFileName.hwndOwner = hwnd;
OpenFileName.hInstance = g_hInst;
OpenFileName.lpstrFilter = (PTSTR)filters;
OpenFileName.lpstrCustomFilter = NULL;
OpenFileName.nMaxCustFilter = 0;
OpenFileName.nFilterIndex = 1;
OpenFileName.lpstrFile = files;
OpenFileName.nMaxFile = _MAX_PATH;
OpenFileName.lpstrFileTitle = NULL;
OpenFileName.lpstrInitialDir = InitialDir;
OpenFileName.lpstrTitle = (PTSTR)title;
OpenFileName.Flags = *pFlags;
OpenFileName.lpstrDefExt = (PTSTR)NULL;
OpenFileName.lCustData = 0L;
OpenFileName.lpfnHook = lpDlgHook;
g_nBoxCount++;
switch (titleId)
{
case DLG_Open_Filebox_Title:
_tcscat(OpenFileName.lpstrFile, defExt);
// fall thru
case DLG_Browse_Executable_Title:
case DLG_Browse_CrashDump_Title:
result = GetOpenFileName((LPOPENFILENAME)&OpenFileName) ;
break ;
case DLG_Browse_LogFile_Title:
if (fileName)
{
_tcscpy(OpenFileName.lpstrFile, fileName);
}
else
{
*OpenFileName.lpstrFile = 0;
}
result = GetOpenFileName((LPOPENFILENAME)&OpenFileName) ;
break;
case DLG_Browse_DbugDll_Title:
*(OpenFileName.lpstrFile) = _T('\0');
result = GetOpenFileName((LPOPENFILENAME)&OpenFileName) ;
break ;
case DLG_Browse_Filebox_Title:
_tsplitpath (files, (PTSTR)NULL, (PTSTR)NULL, (PTSTR)szBase, szExt);
indx = matchExt (szExt, filters);
if (indx != -1)
{
OpenFileName.nFilterIndex = indx;
}
_tcscat(title, szBase);
if (*szExt)
{
_tcscat(title, szExt);
}
FAddToSearchPath = FALSE;
FAddToRootMap = FALSE;
result = GetOpenFileName((LPOPENFILENAME)&OpenFileName) ;
//
// Check to see if the use said to add a file to the browse path.
// If so then add it to the front of the path
//
/*if (FAddToSearchPath)
{
AddToSearchPath(OpenFileName.lpstrFile);
}
else if (FAddToRootMap)
{
RootSetMapped(fileName, OpenFileName.lpstrFile);
}*/
break;
default:
Assert(FALSE);
free(LocalInitialDir);
return FALSE;
}
g_nBoxCount--;
if (result)
{
_tcscpy(fileName, OpenFileName.lpstrFile);
if (titleId == DLG_Open_Filebox_Title)
{
AddFileToMru(FILE_USE_SOURCE, fileName);
}
//
// Get the output of flags
//
*pFlags = OpenFileName.Flags ;
}
//
//Restore cursor
//
SetCursor(hSaveCursor);
free(LocalInitialDir);
return result;
} /* StartFileDlg() */
/*** matchExt
**
** Synopsis:
** int = matchExt (queryExtension, sourceList)
**
** Entry:
**
** Returns: 1-based index of pairwise substring for which the second
** element (i.e., the extension list), contains the target
** extension. If there is no match, we return -1.
**
** Description:
** Searches extension lists for the Open/Save/Browse common
** dialogs to try to match a filter to the input filename's
** extension.
** (Open File, Save File, Merge File and Open Project)
**
** Implementation note: Our thinking looks like this:
**
** We are given a sequence of null-terminated strings which
** are text/extension pairs. We return the pairwise 1-based
** index of the first pair for which the second element has an
** exact match for the target extension. (Everything, by the
** way, is compared without case sensitivity.) We picture the
** source sequence, then, to be an array whose elements are pairs
** of strings (we will call the pairs 'left' and 'right').
**
** Just to complicate things, we allow the '.right' pair elements to
** be strings like "*.c;*.cpp;*.cxx", where we our query might be
** any one of the three (minus the leading asterisk). Fortunately,
** _tcstok() will break things apart for us (see the 'delims[]' array
** in the code for the delimiters we have chosen).
**
** Assuming there is a match in there somewhere, our invariant
** for locating the first one will be:
**
** Exists(k):
** ForAll(i) : 0 <= i < k
** : queryExtension \not IS_IN source[i].right
** \and
** queryExtension IS_IN source[k].right
**
** where we define IS_IN to be a membership predicate (using _tcstok()
** and _tcsicmp() in the implementation, eh?):
**
** x IS_IN y
** <=>
** Exists (t:token) : (t \in y) \and (x == t).
**
** The guard for our main loop, then, comes from the search for the
** queryExtension within the tokens inside successive '.right' elements.
** We choose to continue as long as there is no current token in the
** pair's right side that contains the query.
**
** (We have the pragmatic concern that the value may not be there, so we
** augment the loop guard with the condition that we have not yet
** exhausted the source. This is straightforward to add to the
** invariant, but it causes a lot of clutter that does help our
** comprehension at all, so we just stick it in the guard without
** formal justification.)
*/
int
matchExt(
PTSTR queryExtension,
PTSTR sourceList
)
{
int answer;
int idxPair = 1; // a 1-based index!
PTSTR tokenMatch = 0;
TCHAR delims[] = _T("*,; ") ; // Given a typical string: "*.c;*.cpp;*.cxx",
// _tcstok() would produce three tokens:
// ".c", ".cpp", and ".cxx".
while (*sourceList != 0 && tokenMatch == 0)
{
while (*sourceList != _T('\0'))
{ sourceList++; } // skip first string of pair
sourceList++; // and increment beyond NULL
if (*sourceList != _T('\0'))
{
PTSTR work = _tcsdup (sourceList); // copy to poke holes in
tokenMatch = _tcstok (work, delims);
while (tokenMatch && _tcsicmp (tokenMatch, queryExtension))
{
tokenMatch = _tcstok (0, delims);
}
free (work);
}
if (tokenMatch == 0) // no match: need to move to next pair
{
while (*sourceList != _T('\0'))
{ sourceList++; } // skip second string of pair
sourceList++; // and increment beyond NULL
idxPair++;
}
}
answer = (tokenMatch != 0) ? idxPair : (-1);
return (answer);
}
/*** DlgFile
**
** Synopsis:
** bool = DlgFile(hDlg, message, wParam, lParam)
**
** Entry:
**
** Returns:
**
** Description:
** Processes messages for file dialog boxes
** Those dialogs are not called directly but are called
** by the DlgFile function which contains all basic
** elements for Dialogs Files Operations Handling.
** (Open File, Save File, Merge File and Open Project)
**
** See OFNHookProc
*/
UINT_PTR
APIENTRY
DlgFile(
HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
switch (uMsg)
{
case WM_NOTIFY:
{
LPOFNOTIFY lpon = (LPOFNOTIFY) lParam;
//
// Determine what happened/why we are being notified
//
switch (lpon->hdr.code)
{
case CDN_HELP:
// Help button pushed
Dbg(HtmlHelp(hDlg,g_HelpFileName, HH_HELP_CONTEXT,
g_CurHelpId));
break;
}
}
break;
}
return FALSE;
} /* DlgFile() */
UINT_PTR
APIENTRY
GetOpenFileNameHookProc(
HWND hDlg,
UINT msg,
WPARAM wParam,
LPARAM lParam
)
/*++
Routine Description:
This routine is handle the Add Directory To radio buttons in the
browser source file dialog box.
Arguments:
hDlg - Supplies the handle to current dialog
msg - Supplies the message to be processed
wParam - Supplies info about the message
lParam - Supplies info about the message
Return Value:
TRUE if we replaced default processing of the message, FALSE otherwise
--*/
{
/*
switch( msg ) {
case WM_INITDIALOG:
return TRUE;
case WM_NOTIFY:
{
LPOFNOTIFY lpon = (LPOFNOTIFY) lParam;
switch(lpon->hdr.code) {
case CDN_FILEOK:
FAddToSearchPath = (IsDlgButtonChecked( hDlg, IDC_CHECK_ADD_SRC_ROOT_MAPPING) == BST_CHECKED);
return 0;
}
}
}
return DlgFile(hDlg, msg, wParam, lParam);
*/
return 0;
} /* GetOpenFileNameHookProc() */
void
Internal_Activate(
HWND hwndCur,
HWND hwndNew,
int nPosition
)
/*++
Routine Description:
Places a window in the specified Z order position.
Arguments:
hwndCur - Currently active window, topmost in Z order. Can be NULL.
hwndNew - The window to be placed in the new Z order.
nPosition - Where the window is to be place in the Z order.
1 - topmost
2 - 2nd place (behind topmost)
3 - 3rd place, etc....
Return Value:
None
--*/
{
// Sanity check. Make sure the programmer
// specified a 1, 2, or 3. We are strict in order to
// keep it readable.
Assert(1 <= nPosition && nPosition <= 3);
Assert(hwndNew);
switch (nPosition) {
case 1:
// Make it topmost
SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndNew, 0);
break;
case 2:
// Try to place it 2nd in Z order
if (NULL == hwndCur) {
// We don't have a topmost window, so make this one the topmost window
SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndNew, 0);
} else {
// Place it in 2nd
SetWindowPos(hwndNew, hwndCur, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
// Give the topmost most focus again and activate UI visual clues.
SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndCur, 0);
}
break;
case 3:
// Try to place it 3rd in Z order
if (NULL == hwndCur) {
// We don't have a topmost window, so make this one the topmost window
SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndNew, 0);
} else {
// Is there a window 2nd in the Z order?
HWND hwndPlaceAfter = GetNextWindow(hwndCur, GW_HWNDNEXT);
if (NULL == hwndPlaceAfter) {
// No window 2nd in Z order. Then simply place it after the
// topmost window.
hwndPlaceAfter = hwndCur;
}
// Place it
SetWindowPos(hwndNew, hwndPlaceAfter, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
// Give the topmost most focus again and activate UI visual clues.
SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndCur, 0);
}
break;
default:
// Sanity check, the programmer missed a case
Assert(0);
}
}
void
ActivateMDIChild(
HWND hwndNew,
BOOL bUserActivated
)
/*++
Routine Description:
Used to activate a specified window. Automatically uses the hwndActive
variable to determine the currently active window.
Arguments:
hwndNew - The window to be placed in the new Z order.
bUserActivated - Indicates whether this action was initiated by the
user or by windbg. The value is to determine the Z order of
any windows that are opened.
--*/
{
if (hwndNew == NULL)
{
Assert(hwndNew);
return;
}
HWND hwndPrev = NULL;
PCOMMONWIN_DATA pCur_WinData = NULL;
PCOMMONWIN_DATA pNew_WinData = NULL;
PCOMMONWIN_DATA pPrev_WinData = NULL;
HWND hwndCur = MDIGetActive(g_hwndMDIClient, NULL);
if (!hwndCur || bUserActivated || hwndCur == hwndNew)
{
// Nothing else was open. So we make this one the
// topmost window.
//
// Or the user requested that this window be made
// the topmost window, and we obey.
//
// Or we are re-activating the current window.
Internal_Activate(hwndCur, hwndNew, 1);
return;
}
// See is we have 3 or more windows open
hwndPrev = GetNextWindow(hwndCur, GW_HWNDNEXT);
if (hwndCur)
{
pCur_WinData = GetCommonWinData(hwndCur);
}
pNew_WinData = GetCommonWinData(hwndNew);
Assert(pNew_WinData);
if (!pNew_WinData)
{
return;
}
if (hwndPrev)
{
pPrev_WinData = GetCommonWinData(hwndPrev);
}
//
// Handle the case where the window activation
// was requested by the debugger itself and not the
// user.
//
switch (pNew_WinData->m_enumType)
{
default:
Internal_Activate(hwndCur, hwndNew, bUserActivated ? 2 : 1);
break;
case DISASM_WINDOW:
case DOC_WINDOW:
if (GetSrcMode_StatusBar())
{
// Src mode
if (pCur_WinData != NULL &&
(DISASM_WINDOW == pCur_WinData->m_enumType ||
DOC_WINDOW == pCur_WinData->m_enumType))
{
// We can take the place of another doc/asm wind
// Place 1st in z-order
Internal_Activate(hwndCur, hwndNew, 1);
}
else
{
if (pPrev_WinData != NULL &&
(DOC_WINDOW == pPrev_WinData->m_enumType ||
DISASM_WINDOW == pPrev_WinData->m_enumType))
{
// Don't have a window in 2nd place, or if we do it
// is a src or asm window, and we can hide it.
// Place 2nd in Z-order
Internal_Activate(hwndCur, hwndNew, 2);
}
else
{
// Place 3rd in Z-order
Internal_Activate(hwndCur, hwndNew, 3);
}
}
}
else
{
WIN_TYPES Type = pCur_WinData != NULL ?
pCur_WinData->m_enumType : MINVAL_WINDOW;
// Asm mode
// Which is currently the topmost window.
switch (Type)
{
case DOC_WINDOW:
// Place 1st in z-order
Internal_Activate(hwndCur, hwndNew, 1);
break;
case DISASM_WINDOW:
if (DOC_WINDOW == pNew_WinData->m_enumType)
{
if (pPrev_WinData == NULL ||
DOC_WINDOW != pPrev_WinData->m_enumType)
{
// We have a window in second place that isn't a doc
// window (locals, watch, ...).
Internal_Activate(hwndCur, hwndNew, 3);
}
else
{
// Either don't have any windows in second place, or
// we have a window in second place that is a doc
// window. We can take its place.
//
// Place 2nd in z-order
Internal_Activate(hwndCur, hwndNew, 2);
}
}
else
{
// Should never happen. The case of disasm being activated
// when it is currently active should ahve already been
// taken care of.
Dbg(0);
}
break;
default:
if ((pPrev_WinData != NULL &&
DISASM_WINDOW == pPrev_WinData->m_enumType) &&
DOC_WINDOW == pNew_WinData->m_enumType)
{
// window (locals, watch, ...).
Internal_Activate(hwndCur, hwndNew, 3);
}
else
{
// Place 2nd in z-order
Internal_Activate(hwndCur, hwndNew, 2);
}
break;
}
}
break;
}
}
void
AppendTextToAnEditControl(
HWND hwnd,
PTSTR pszNewText
)
{
Assert(hwnd);
Assert(pszNewText);
CHARRANGE chrrgCurrent = {0};
CHARRANGE chrrgAppend = {0};
// Get the current selection
SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) &chrrgCurrent);
// Set the selection to the very end of the edit control
chrrgAppend.cpMin = chrrgAppend.cpMax = GetWindowTextLength(hwnd);
SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &chrrgCurrent);
// Append the text
SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM) pszNewText);
// Restore previous selection
SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &chrrgCurrent);
}
VOID
CopyToClipboard(
PSTR str
)
{
if (!str)
{
return;
}
ULONG Len = strlen(str)+1;
HANDLE Mem = GlobalAlloc(GMEM_MOVEABLE, Len);
if (Mem == NULL)
{
return;
}
PSTR Text = (PSTR)GlobalLock(Mem);
if (Text == NULL)
{
GlobalFree(Mem);
return;
}
strcpy(Text, str);
GlobalUnlock(Mem);
if (OpenClipboard(NULL))
{
EmptyClipboard();
if (SetClipboardData(CF_TEXT, Mem) == NULL)
{
GlobalFree(Mem);
}
CloseClipboard();
}
}
void
SetAllocString(PSTR* Str, PSTR New)
{
if (*Str != NULL)
{
free(*Str);
}
*Str = New;
}
BOOL
DupAllocString(PSTR* Str, PSTR New)
{
PSTR NewStr = (PSTR)malloc(strlen(New) + 1);
if (NewStr == NULL)
{
return FALSE;
}
strcpy(NewStr, New);
SetAllocString(Str, NewStr);
return TRUE;
}
BOOL
PrintAllocString(PSTR* Str, int Len, PCSTR Format, ...)
{
PSTR NewStr = (PSTR)malloc(Len);
if (NewStr == NULL)
{
return FALSE;
}
va_list Args;
va_start(Args, Format);
_vsnprintf(NewStr, Len, Format, Args);
va_end(Args);
SetAllocString(Str, NewStr);
return TRUE;
}
HMENU
CreateContextMenuFromToolbarButtons(ULONG NumButtons,
TBBUTTON* Buttons,
ULONG IdBias)
{
ULONG i;
HMENU Menu;
Menu = CreatePopupMenu();
if (Menu == NULL)
{
return Menu;
}
for (i = 0; i < NumButtons; i++)
{
MENUITEMINFO Item;
ZeroMemory(&Item, sizeof(Item));
Item.cbSize = sizeof(Item);
Item.fMask = MIIM_TYPE;
if (Buttons->fsStyle & BTNS_SEP)
{
Item.fType = MFT_SEPARATOR;
}
else
{
Item.fMask |= MIIM_ID;
Item.fType = MFT_STRING;
Item.wID = (WORD)(Buttons->idCommand + IdBias);
Item.dwTypeData = (LPSTR)Buttons->iString;
}
if (!InsertMenuItem(Menu, i, TRUE, &Item))
{
DestroyMenu(Menu);
return NULL;
}
Buttons++;
}
DrawMenuBar(g_hwndFrame);
return Menu;
}
HWND
AddButtonBand(HWND Bar, PTSTR Text, PTSTR SizingText, UINT Id)
{
HWND Button;
HDC Dc;
RECT Rect;
Button = CreateWindowEx(0, "BUTTON", Text, WS_VISIBLE | WS_CHILD,
0, 0, 0, 0,
Bar, (HMENU)(UINT_PTR)Id, g_hInst, NULL);
if (Button == NULL)
{
return NULL;
}
Rect.left = 0;
Rect.top = 0;
SendMessage(Button, WM_SETFONT, (WPARAM)g_Fonts[FONT_VARIABLE].Font, 0);
Dc = GetDC(Button);
if (Dc != NULL)
{
SIZE Size;
GetTextExtentPoint32(Dc, SizingText, strlen(SizingText), &Size);
Rect.right = Size.cx;
Rect.bottom = Size.cy;
ReleaseDC(Button, Dc);
}
else
{
Rect.right = strlen(Text) * g_Fonts[FONT_FIXED].Metrics.tmAveCharWidth;
Rect.bottom = g_Fonts[FONT_FIXED].Metrics.tmHeight;
}
REBARBANDINFO BandInfo;
BandInfo.cbSize = sizeof(BandInfo);
BandInfo.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE;
BandInfo.fStyle = RBBS_FIXEDSIZE;
BandInfo.hwndChild = Button;
BandInfo.cxMinChild = Rect.right - Rect.left +
4 * GetSystemMetrics(SM_CXEDGE);
BandInfo.cyMinChild = Rect.bottom - Rect.top +
2 * GetSystemMetrics(SM_CYEDGE);
SendMessage(Bar, RB_INSERTBAND, -1, (LPARAM)&BandInfo);
return Button;
}