Windows2000/private/windbg64/windbg/watchwin.c
2020-09-30 17:12:32 +02:00

877 lines
20 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
watchwin.c
Abstract:
This module contains the routines to manipulate the Watch Window
Author:
William J. Heaton (v-willhe) 20-Jul-1992
Griffith Wm. Kadnier (v-griffk) 10-Mar-1993
Environment:
Win32, User Mode
--*/
#include "precomp.h"
#pragma hdrstop
/*
* Global Memory (PROGRAM)
*/
extern CXF CxfIp;
char output[512];
/*
* Global Memory (FILE)
*/
PTRVIT pvitWatch;
HWND hWndWatch;
VOID WatchUpdate( PPANE p, BOOL fClear, WPARAM wParam);
BOOL AcceptValueUpdate(PTRVIT pVit,PPANE p);
extern LRESULT SendMessageNZ (HWND,UINT,WPARAM,LPARAM);
/*** InitWatchVit
** Synopsis:
** pVit = InitWatchVit()
** Entry:
** None
** Returns:
** Returns a pointer to the current vit (Allocating one if needed).
** return NULL if can't
** Description:
** Creates the Vit (Variable Information Top) block for the
** watch window
*/
PTRVIT PASCAL InitWatchVit(void)
{
if (pvitWatch == NULL) {
pvitWatch = (PTRVIT) calloc(1, sizeof(VIT));
}
return (pvitWatch);
} /* InitWatchVit() */
/*** GetWatchVit
** Synopsis:
** pVit = GetWatchVit()
** Entry:
** None
** Returns:
** Pointer to the current watch vit.
*/
PTRVIT GetWatchVit(VOID)
{
return(pvitWatch);
}
/*** GetWatchHWND
** Synopsis:
** hWnd = GetWatchHWND()
** Entry:
** None
** Returns:
** Pointer to the current watch window handle.
*/
HWND GetWatchHWND(VOID)
{
return(hWndWatch);
}
/*** UpdateCVWatchs
** Synopsis:
** UpdateCVWatchs()
** Entry:
** Returns:
** Description:
** Forces the WatchWindow (If Present) to update ALL of its
** Panels.
*/
VOID UpdateCVWatchs()
{
PPANE p;
if ( hWndWatch ) {
p = (PPANE)GetWindowLongPtr(hWndWatch, GWW_EDIT );
p->LeftOk = p->RightOk = FALSE;
}
UpdateDebuggerState( UPDATE_WATCH );
return;
}
/*** AddCVWatch
** Synopsis:
** pVib = AddCVWatch(PSTR szExpStr)
** Entry:
** szExpStr - A pointer to the string containing the entry to
** be added.
** Returns:
** Return a pointer to the vib created or NULL;
** Description:
** Adds a expression to the watch window. Returns the VIB created.
*/
PTRVIB AddCVWatch(PTRVIT pVit, PSTR szExpStr)
{
VIB vibT = {0};
PTRVIB pvib;
// check to see if the watch vit is there yet or not
// this is for the state file.
if ( pVit == (PTRVIT)NULL) {
FTError(UNABLETOADDWATCH);
return(NULL);
}
// make a dummy vib
vibT.pvibSib = pVit->pvibChild;
pvib = &vibT;
// find the end of the chain
while( pvib->pvibSib != NULL) {
pvib = pvib->pvibSib;
}
// set the current context
if( FTMakeWatchEntry(&pvib->pvibSib, pVit, szExpStr) ) {
return(NULL);
}
// add this entry to the vit
FTclnUpdateParent(pvib->pvibSib->pvibParent, 1);
// restore the vit
pVit->pvibChild = vibT.pvibSib;
return(pvib->pvibSib);
} /* AddCVWatch() */
/*** DeleteCVWatch
** Synopsis:
** LTS = DeleveCVWatch(PTRVIT pVit, PTRVIB pvib)
** Entry:
** pVib - Pointer to the VIB that contains the watch to
** delete.
** Returns:
** Returns a LTS status code (defined in vib.h)
** Description:
** Given a pointer to a vib, find it and delete it from the
** watch tree.
*/
LTS DeleteCVWatch(PTRVIT pVit, PTRVIB pvib)
{
VIB vibT;
PTRVIB pvibPrev;
// make sure this is a watch to be deleted
if (!(pvib && (pvib->vibPtr == vibWatch
|| pvib->vibPtr == vibType))) {
return UNABLETODELETEWATCH;
}
// starting at the head of the list, find the previous vib
vibT.pvibSib = pVit->pvibChild;
pvibPrev = &vibT;
while (pvibPrev->pvibSib != pvib) {
pvibPrev = pvibPrev->pvibSib;
}
// remove this the deleted one from the chain
pvibPrev->pvibSib = pvib->pvibSib;
pvib->pvibSib = NULL;
// update the the vit with the new chain
pVit->pvibChild = vibT.pvibSib;
// delete all members of this vib from the parent count
FTclnUpdateParent(pvib->pvibParent, -pvib->cln );
// delete this vib, and all children
FTFreeAllSib(pvib);
pvib = NULL;
return OK;
} /* DeleteCVWatch() */
/*** ReplaceCVWatch
** Synopsis:
** bool = ReplaceCVWatch( pvit, pvib, szStr)
** Entry:
** pvib - Pointer to the VIB whos expression is changing
** szStr - Pointer to the New expression string.
** Returns:
** TRUE or FALSE
** Description:
** Replaces the expression strings of the indicated watch
** entry with the new string.
*/
BOOL ReplaceCVWatch(PTRVIT pVit, PTRVIB pvib, PSTR szStr)
{
PTRVIB *ppvib;
// Find The parent VIB
ppvib = &pVit->pvibChild;
while ( *ppvib && *ppvib != pvib ) {
ppvib = &(*ppvib)->pvibSib;
}
// Make a New child for the parent
if ( ! FTMakeWatchEntry ( ppvib, pVit, szStr) ) {
// New Child gets the Old Child's siblings
FTVerify(&pVit->cxf,*ppvib);
(*ppvib)->pvibSib = pvib->pvibSib;
FTclnUpdateParent( (*ppvib)->pvibParent, (*ppvib)->cln );
// Remove the Old Child
FTclnUpdateParent(pvib->pvibParent, -pvib->cln);
pvib->pvibSib = NULL;
FTFreeAllSib(pvib);
pvib = (PTRVIB) NULL;
return(TRUE);
} else {
// Couldn't add the new watch, make sure the old stays around
*ppvib = pvib;
return(FALSE);
}
}
/*** AcceptWatchUpdate
** Synopsis:
** Entry:
** Returns:
** Description:
*/
BOOL AcceptWatchUpdate(PTRVIT pVit,PPANE p, WPARAM wParam)
{
PSTR pszBuffer;
PTRVIB EditVib;
HWND hWnd = p->hWndLeft;
ULONG Line = (LONG)p->CurIdx;
BOOL retVal = FALSE;
// Get the current line number, and contents, find its vib
pszBuffer = p->EditBuf;
while ( isspace(*pszBuffer) ) {
pszBuffer++;
}
EditVib = FTvibGetAtLine(pVit,Line);
// Does a Vib exist for this line, if so we're deleting or changing it
if ( EditVib ) {
// It only makes sense to modify level zero things.
if (EditVib->level == 0 ) {
if ( *pszBuffer ) {
retVal = ReplaceCVWatch( pVit, EditVib, pszBuffer);
if (p->bFlags.Expand1st)
EditVib->flags.ExpandMe = TRUE;
p->LeftOk = p->RightOk = FALSE;
WatchUpdate(p, FALSE, wParam);
}
else {
// Blanking the name means remove the watch
DeleteCVWatch(pVit, EditVib);
// We Need to repaint, watch count changed
p->LeftOk = p->RightOk = FALSE;
WatchUpdate(p, FALSE, wParam);
retVal = TRUE;
}
}
} else {
// Vib doesn't exist for this line create it.
if (*pszBuffer && (EditVib = AddCVWatch(pVit, pszBuffer)) != NULL) {
p->CurIdx++;
if (p->bFlags.Expand1st) {
EditVib->flags.ExpandMe = TRUE;
}
// We Need to repaint, watch count changed
p->LeftOk = p->RightOk = FALSE;
WatchUpdate(p, FALSE, wParam);
retVal = TRUE;
}
}
return retVal;
} /* AcceptWatchUpdate() */
/*** AcceptValueUpdate
** Synopsis:
** Entry:
** Returns:
** Description:
*/
BOOL AcceptValueUpdate(PTRVIT pVit,PPANE p)
{
PSTR pszBuffer;
PTRVIB pVib;
EESTATUS eeErr;
HTM hTm;
ULONG strIndex;
VPI i;
EEHSTR hstr;
DWORD cb;
char * lpsz;
EERADIX uradix = radix;
// If we're not editing, we're done (sucessfully)
if ( !p->Edit ) {
return(TRUE);
}
/*
* Get the expression represented by the left pane
*/
pVib = FTvibGetAtLine(pVit,p->CurIdx);
if (pVib->hTMBd == 0) {
hTm = pVib->pvtext[pVib->vibIndex].htm;
} else {
hTm = pVib->hTMBd;
}
if (EEGetExprFromTM(&hTm, &uradix, &hstr, &cb) != EENOERROR) {
return FALSE;
}
if (cb >= sizeof(output)-3) {
return FALSE;
}
lpsz = (PSTR) MMLpvLockMb( hstr );
output[0] = '(';
strncpy(&output[1], lpsz, cb);
strcpy(&output[cb+1], ")=");
MMbUnlockMb( hstr );
EEFreeStr( hstr );
// Get the New values
pszBuffer = p->EditBuf;
DAssert(pszBuffer);
while ( isspace(*pszBuffer) ) {
pszBuffer++;
}
if ((strlen(pszBuffer) + cb + 3) > sizeof(output)) {
return FALSE;
}
strcat(output, pszBuffer);
// Parse, Bind, and Evaluate
eeErr = EEParse(output, radix, fCaseSensitive, &hTm, &strIndex);
if (eeErr == EENOERROR) {
eeErr = EEBindTM(&hTm, SHpCXTFrompCXF(&CxfIp), TRUE, FALSE);
}
if (eeErr == EENOERROR) {
eeErr = EEvaluateTM(&hTm, SHhFrameFrompCXF(&CxfIp), EEHORIZONTAL);
}
if (hTm) {
EEFreeTM( &hTm );
}
if (eeErr == EENOERROR) {
i = pVib->vibIndex;
FTEnsureTextExists(pVib);
if(pVib->pvtext[i].pszValueP) {
free(pVib->pvtext[i].pszValueP);
}
pVib->pvtext[i].pszValueP = pVib->pvtext[i].pszValueC;
pVib->pvtext[i].pszValueC = NULL;
return(TRUE);
}
MessageBeep(0);
return(FALSE);
} /* AcceptValueUpdate() */
/*** WatchEditProc
** Synopsis:
** lresult = WatchEditProc(hwnd, msg, wParam, lParam)
** Entry:
** hwnd - handle to window to process message for
** msg - message to be processed
** wParam - information about message to be processed
** lParam - information about message to be processed
** Returns:
** Description:
** MDI function to handle Watch window messages
*/
LRESULT
CALLBACK
WatchEditProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
)
{
PPANE p = (PPANE)lParam;
PPANEINFO pInfo = (PPANEINFO)wParam;
PTRVIB pVib = NULL;
PVTEXT pvtext;
__try {
switch (msg) {
case WU_INITDEBUGWIN:
Dbg(InitWatchVit());
hWndWatch = hwnd;
SendMessage(p->hWndLeft, LB_SETCOUNT, 1, 0);
SendMessage(p->hWndButton, LB_SETCOUNT, 1, 0);
SendMessage(p->hWndRight, LB_SETCOUNT, 1, 0);
p->MaxIdx = (WORD)1;
WatchUpdate(p, FALSE, wParam);
break;
case WM_DESTROY:
hWndWatch = NULL;
// Fall thru...
case WU_DBG_UNLOADEE:
case WU_DBG_UNLOADEM:
// Lose the Watch Tree
if ( pvitWatch && pvitWatch->pvibChild ) {
FTFreeAllSib(pvitWatch->pvibChild);
pvitWatch->pvibChild = NULL;
free(pvitWatch);
pvitWatch = NULL;
SendMessage(p->hWndLeft, LB_SETCOUNT, 1, 0);
SendMessage(p->hWndButton, LB_SETCOUNT, 1, 0);
SendMessage(p->hWndRight, LB_SETCOUNT, 1, 0);
p->MaxIdx = (WORD)1;
WatchUpdate(p, FALSE, wParam);
}
break;
case WU_DBG_LOADEM:
case WU_DBG_LOADEE:
if (!pvitWatch) {
Dbg(InitWatchVit());
hWndWatch = hwnd;
SendMessage(p->hWndLeft, LB_SETCOUNT, 1, 0);
SendMessage(p->hWndButton, LB_SETCOUNT, 1, 0);
SendMessage(p->hWndRight, LB_SETCOUNT, 1, 0);
p->MaxIdx = (WORD)1;
WatchUpdate(p, FALSE, wParam);
}
break;
case WU_INVALIDATE:
if (p == (PPANE)NULL) {
p = (PPANE)GetWindowLongPtr(GetWatchHWND(), GWW_EDIT );
}
SendMessage(p->hWndLeft, LB_SETCOUNT, 0, 0);
SendMessage(p->hWndButton, LB_SETCOUNT, 0, 0);
SendMessage(p->hWndRight, LB_SETCOUNT, 0, 0);
p->MaxIdx = 0;
WatchUpdate(p, FALSE, wParam);
InvalidateRect(p->hWndButton, NULL, TRUE);
InvalidateRect(p->hWndLeft, NULL, TRUE);
InvalidateRect(p->hWndRight, NULL, TRUE);
UpdateWindow (p->hWndButton);
UpdateWindow (p->hWndLeft);
UpdateWindow (p->hWndRight);
break;
case WU_OPTIONS:
pVib = FTvibGetAtLine( pvitWatch, pInfo->ItemId);
if ( pVib == NULL) {
return(FALSE);
}
pvtext = &pVib->pvtext[pVib->vibIndex];
if ( pInfo->pFormat && (*(pvtext->pszValueC) != '{') ) {
FTEnsureTextExists(pVib);
if ( pvtext->pszFormat) {
free(pvtext->pszFormat);
}
pvtext->pszFormat = _strdup(pInfo->pFormat);
if ( pvtext->pszValueC) {
free(pvtext->pszValueC);
}
pvtext->pszValueC = NULL;
PaneInvalidateRow(p);
} else {
FTEnsureTextExists(pVib);
if (pvtext->pszFormat) {
free(pvtext->pszFormat);
}
pvtext->pszFormat = '\0';
if ( pvtext->pszValueC) {
free(pvtext->pszValueC);
}
pvtext->pszValueC = NULL;
PaneInvalidateRow(p);
}
return TRUE;
case WU_INFO:
pInfo->pBuffer = pInfo->pFormat = NULL;
pInfo->NewText = FALSE;
pInfo->ReadOnly = (pInfo->CtrlId == ID_PANE_LEFT) ? FALSE : TRUE;
pVib = FTvibGetAtLine( pvitWatch, pInfo->ItemId);
if ( pVib == NULL) {
return(FALSE);
}
FTEnsureTextExists(pVib);
pvtext = &pVib->pvtext[pVib->vibIndex];
pInfo->pFormat = pvtext->pszFormat;
pInfo->pBuffer = FTGetPanelString( pvitWatch, pVib, pInfo->CtrlId);
pInfo->ReadOnly = (pInfo->ItemId == (UINT) p->MaxIdx);
if ( pInfo->CtrlId == ID_PANE_LEFT ) {
pInfo->NewText = FALSE;
} else if ( pInfo->CtrlId == ID_PANE_RIGHT) {
pInfo->NewText = FTGetPanelStatus( pVib, pInfo->CtrlId);
} else {
pInfo->ReadOnly = TRUE;
pInfo->NewText = FALSE;
}
return TRUE;
case WU_SETWATCH:
if (pvitWatch == NULL) {
return(FALSE);
}
if (p->nCtrlId == ID_PANE_LEFT) {
return(AcceptWatchUpdate( pvitWatch, p, wParam));
} else {
BOOL retval;
retval = (AcceptValueUpdate( pvitWatch, p));
if (retval == TRUE) {
UpdateDebuggerState(UPDATE_DATAWINS);
}
return retval;
}
break;
case WU_EXPANDWATCH:
if (pvitWatch == NULL) {
return(FALSE);
}
if ( FTExpand(pvitWatch, (ULONG)(wParam)) == OK) {
p->LeftOk = p->RightOk = FALSE;
WatchUpdate(p, FALSE, wParam); // Watch Count changed
}
break;
case WU_UPDATE:
WatchUpdate(p, (BOOL)wParam, wParam);
break;
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
return FALSE;
}
return FALSE;
}
VOID
WatchUpdate(
PPANE p,
BOOL fClear,
WPARAM wParam
)
{
LONG Len = 0;
LRESULT lLen = 0;
WORD i;
RECT Rect, tRect;
HWND hFoc;
HCURSOR hOldCursor, hWaitCursor;
if ( pvitWatch == NULL) {
return;
}
// Set hourglass cursor
hWaitCursor = LoadCursor (NULL, IDC_WAIT);
hOldCursor = SetCursor (hWaitCursor);
hFoc = GetFocus();
if ( FTVerify(&CxfIp, pvitWatch->pvibChild) ) {
p->LeftOk = FALSE;
}
pvitWatch->cxf = CxfIp;
// Always repaint the watch window.
if ( p->bFlags.Expand1st) {
FTExpandOne(pvitWatch->pvibChild);
}
Len = (LONG)pvitWatch->cln + 1;
lLen = SendMessage(p->hWndLeft, LB_GETCOUNT, 0, 0L);
if ((lLen < Len) || (lLen == 0)) {
SendMessage(p->hWndLeft, LB_SETCOUNT, Len, 0);
SendMessage(p->hWndButton, LB_SETCOUNT, Len, 0);
SendMessage(p->hWndRight, LB_SETCOUNT, Len, 0);
} else {
SendMessage(p->hWndLeft, LB_SETCOUNT, (WPARAM) ((int)lLen), 0L);
SendMessage(p->hWndButton, LB_SETCOUNT, (WPARAM) ((int)lLen), 0L);
SendMessage(p->hWndRight, LB_SETCOUNT, (WPARAM) ((int)lLen), 0L);
}
p->MaxIdx = (WORD)Len;
// Reseting the count, lost where we were so put us back
if (p->MaxIdx > 0) {
PaneResetIdx(p,p->CurIdx);
}
p->LeftOk = TRUE;
// Reset the right pane
FTAgeVibValues(pvitWatch->pvibChild);
for ( i= p->TopIdx; i < (p->TopIdx + p->PaneLines) ; i++) {
if ( FTVerifyNew(pvitWatch, i) ) {
PaneInvalidateItem( p->hWndRight, p, i);
}
}
p->RightOk = TRUE;
PaneCaretNum(p);
if ((hFoc == p->hWndButton) || (hFoc == p->hWndLeft) || (hFoc == p->hWndRight)) {
SendMessage(p->hWndButton , LB_GETITEMRECT, (WPARAM)p->CurIdx, (LPARAM)&Rect);
GetClientRect (p->hWndButton, &tRect);
tRect.top = Rect.top;
InvalidateRect(p->hWndButton, &tRect, TRUE);
SendMessage(p->hWndLeft , LB_GETITEMRECT, (WPARAM)p->CurIdx, (LPARAM)&Rect);
GetClientRect (p->hWndLeft, &tRect);
tRect.top = Rect.top;
InvalidateRect(p->hWndLeft, &tRect, TRUE);
SendMessage(p->hWndRight , LB_GETITEMRECT, (WPARAM)p->CurIdx, (LPARAM)&Rect);
GetClientRect (p->hWndRight, &tRect);
tRect.top = Rect.top;
InvalidateRect(p->hWndRight, &tRect, TRUE);
}
CheckPaneScrollBar( p, (WORD)Len);
// Set original cursor
hOldCursor = SetCursor (hOldCursor);
}
void
ReloadAllWatchVariables()
/*++
Routine Desciption:
Deletes and readds all of the variables to the watch window.
This is basically just a cog in a bigger hack to force the
watch window to work correctly.
--*/
{
PTRVIT pVit = NULL;
PTRVIB pVib = NULL;
LPSTR * alpszExpr = NULL; // Tmp holder for watch expressions. Array of LPSTR
const int nGrowBy = 2; // When the array is full, grow it by this amount.
int nStrArraySize = 0; // Size of alpszExpr
int nNumStringItems = 0; // Current number of strings stored in alpszExpr
int i;
if (!pvitWatch) {
return;
}
// Save all of the strings
for (pVib = pvitWatch->pvibChild; pVib; pVib = pVib->pvibSib) {
if (pVib->pwoj && pVib->pwoj->szExpStr && *pVib->pwoj->szExpStr) {
// Do we need to resize the array
if (nNumStringItems == nStrArraySize) {
PSTR * p = (PSTR *) realloc(alpszExpr, sizeof(LPSTR) * (nStrArraySize + nGrowBy));
if (!p) {
// Array has not been resized. Bail out & lose the rest of the watch expresions.
break;
} else {
// Array has been successfully reallocated. Initialize the new region by
// zeroing it out.
alpszExpr = p;
nStrArraySize += nGrowBy;
memset(&alpszExpr[nNumStringItems], 0, sizeof(LPSTR) * nGrowBy);
}
}
alpszExpr[nNumStringItems] = _strdup(pVib->pwoj->szExpStr);
if (!alpszExpr[nNumStringItems]) {
// Weren't able to allocate mem. Bail out & lose the rest of the watch expressions.
break;
} else {
// String successfully added
nNumStringItems++;
}
}
}
// Delete all the watch variables
SendMessageNZ( GetWatchHWND(), WU_DBG_UNLOADEE, 0, 0L);
// Re-add all of the watch variables
for (i=0; i<nNumStringItems; i++) {
FTAddWatchVariable(&pVit, &pVib, alpszExpr[i]);
free(alpszExpr[i]);
alpszExpr[i] = NULL;
}
if (alpszExpr) {
free(alpszExpr);
}
}