windows-nt/Source/XPSP1/NT/admin/burnslib/spewview/spewdialog.cpp
2020-09-26 16:20:57 +08:00

421 lines
8.4 KiB
C++

// Spewview: remote debug spew monitor
//
// Copyright (c) 2000 Microsoft Corp.
//
// Spew monitoring window: modeless dialog to capture spewage
//
// 16 Mar 2000 sburns
#include "headers.hxx"
#include "SpewDialog.hpp"
#include "MainDialog.hpp"
#include "ReaderThread.hpp"
#include "resource.h"
const int WM_UPDATE_SPEWAGE = WM_USER + 200;
static const DWORD _help_map[] =
{
IDC_START, NO_HELP,
IDC_STOP, NO_HELP,
IDC_SPEWAGE, NO_HELP,
IDC_LINE_COUNTER, NO_HELP,
IDC_SELECT_ALL, NO_HELP,
0, 0
};
SpewDialog::SpewDialog(const String& clientName_, const String& appName_)
:
Dialog(IDD_SPEWAGE, _help_map),
spewLineCount(0),
textBoxLineCount(0),
clientName(clientName_),
appName(appName_),
readerThreadCreated(false),
endReaderThread(0)
{
LOG_CTOR(SpewDialog);
}
SpewDialog::~SpewDialog()
{
LOG_DTOR(SpewDialog);
StopReadingSpewage();
}
void
SpewDialog::OnStartButton()
{
LOG_FUNCTION(SpewDialog::OnStartButton);
if (!readerThreadCreated)
{
Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_START), false);
StartReadingSpewage();
}
}
void
SpewDialog::OnStopButton()
{
LOG_FUNCTION(SpewDialog::OnStopButton);
StopReadingSpewage();
}
bool
SpewDialog::OnCommand(
HWND /* windowFrom */ ,
unsigned controlIDFrom,
unsigned code)
{
switch (controlIDFrom)
{
case IDC_START:
{
if (code == BN_CLICKED)
{
OnStartButton();
return true;
}
break;
}
case IDC_STOP:
{
if (code == BN_CLICKED)
{
OnStopButton();
return true;
}
break;
}
case IDC_SELECT_ALL:
{
break;
}
case IDCANCEL:
{
if (code == BN_CLICKED)
{
// signal the reader thread to die.
StopReadingSpewage();
// signal the main dialog to kill us
Win::PostMessage(
Win::GetParent(hwnd),
MainDialog::WM_KILL_SPEWVIEWER,
0,
0);
return true;
}
break;
}
default:
{
// do nothing
}
}
return false;
}
void
SpewDialog::ResizeSpewWindow(int newParentWidth, int newParentHeight)
{
HRESULT hr = S_OK;
HWND spewWindow = Win::GetDlgItem(hwnd, IDC_SPEWAGE);
do
{
hr =
Win::SetWindowPos(
spewWindow,
0,
0,
0,
newParentWidth - margins.left - margins.right,
newParentHeight - margins.top - margins.bottom,
SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER);
BREAK_ON_FAILED_HRESULT(hr);
}
while (0);
}
bool
SpewDialog::OnMessage(
UINT message,
WPARAM wparam,
LPARAM lparam)
{
switch (message)
{
case WM_UPDATE_SPEWAGE:
{
// lparam is pointer to spewage buffer to dump into the edit
// box.
ASSERT(lparam);
if (lparam)
{
String* spew = reinterpret_cast<String*>(lparam);
ASSERT(!spew->empty());
AppendMessage(wparam, *spew);
delete spew;
}
return true;
}
case WM_ENABLE_START:
{
// The reader thread has disconnected and closed the pipe, and is
// (nearly) dead, so it's ok to allow another reader thread to be
// started.
Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_START), true);
return true;
}
case WM_SIZE:
{
int newDlgWidth = LOWORD(lparam);
int newDlgHeight = HIWORD(lparam);
ResizeSpewWindow(newDlgWidth, newDlgHeight);
return false;
}
default:
{
// do nothing;
break;
}
}
return false;
}
void
SpewDialog::AppendMessage(WPARAM wparam, const String& message)
{
bool isSpew = (wparam != -1);
if (isSpew)
{
++spewLineCount;
Win::SetDlgItemText(
hwnd,
IDC_LINE_COUNTER,
String::format(L"%1!010d!", spewLineCount));
}
Win::Edit_AppendText(
Win::GetDlgItem(hwnd, IDC_SPEWAGE),
isSpew ? message : L">>>> " + message);
++textBoxLineCount;
}
void
SpewDialog::OnInit()
{
LOG_FUNCTION(SpewDialog::OnInit);
Win::SetWindowText(
hwnd,
String::format(
L"Spewage from %1 on machine %2",
appName.c_str(),
clientName.c_str()));
spewLineCount = 0;
Win::SetDlgItemText(
hwnd,
IDC_LINE_COUNTER,
String::format(L"%1!010d!", spewLineCount));
// extend the amount of text that can be inserted into the spew
// rich edit control
HWND spewWindow = Win::GetDlgItem(hwnd, IDC_SPEWAGE);
Win::SendMessage(
spewWindow,
EM_EXLIMITTEXT,
0,
// 256K characters.
(1 << 18));
// Change the font in the spew window to fixed-width
do
{
static String SPEW_FONT_NAME = L"Lucida Console";
LOGFONT logFont;
memset(&logFont, 0, sizeof(LOGFONT));
SPEW_FONT_NAME.copy(
logFont.lfFaceName,
// don't copy over the last null
min(LF_FACESIZE - 1, SPEW_FONT_NAME.length()));
HDC hdc = 0;
HRESULT hr = Win::GetDC(hwnd, hdc);
BREAK_ON_FAILED_HRESULT(hr);
logFont.lfHeight =
- ::MulDiv(8, Win::GetDeviceCaps(hdc, LOGPIXELSY), 72);
Win::ReleaseDC(hwnd, hdc);
HFONT font = 0;
hr = Win::CreateFontIndirect(logFont, font);
BREAK_ON_FAILED_HRESULT(hr);
Win::SetWindowFont(spewWindow, font, false);
}
while (0);
ComputeMargins();
// Disable the start button, as we start upon initialization
Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_START), false);
// Start the reader thread. This will create and connect to the spew
// pipe, and start reading messages from it.
StartReadingSpewage();
}
void
SpewDialog::ComputeMargins()
{
LOG_FUNCTION(SpewDialog::ComputeMargins);
memset(&margins, 0, sizeof(margins));
HRESULT hr = S_OK;
do
{
HWND spewWindow = Win::GetDlgItem(hwnd, IDC_SPEWAGE);
// get the current dimmensions of the dialog
// use the client rect to remove non-client area from consideration
RECT parentRect;
hr = Win::GetClientRect(hwnd, parentRect);
BREAK_ON_FAILED_HRESULT(hr);
hr = Win::MapWindowPoints(hwnd, 0, parentRect);
BREAK_ON_FAILED_HRESULT(hr);
// get the dimmensions of the spew window, relative to the
// parent dialog
RECT spewRect;
hr = Win::GetWindowRect(spewWindow, spewRect);
BREAK_ON_FAILED_HRESULT(hr);
// compute the margins between the spew window and the parent dialog
margins.bottom = parentRect.bottom - spewRect.bottom;
margins.right = parentRect.right - spewRect.right;
margins.left = spewRect.left - parentRect.left;
margins.top = spewRect.top - parentRect.top;
}
while (0);
}
void
SpewDialog::StartReadingSpewage()
{
LOG_FUNCTION(SpewDialog::StartReadingSpewage);
if (!readerThreadCreated)
{
// deleted in readerThreadProc
ReaderThreadParams* params = new ReaderThreadParams;
params->hwnd = hwnd;
params->endFlag = &endReaderThread;
params->appName = appName;
// endReaderThread is shared among this thread and the thread we are
// about to spawn. It does not need guarding, because it is an atomic
// data type (int), and because we do not care about the order in which
// the threads read/write to it. Further, this thread only writes to
// the value, and the reader thread only reads it.
endReaderThread = 0;
// start the reader thread a-runnin'
_beginthread(ReaderThreadProc, 0, params);
readerThreadCreated = true;
}
}
void
SpewDialog::StopReadingSpewage()
{
LOG_FUNCTION(SpewDialog::StopReadingSpewage);
if (readerThreadCreated)
{
// Tell the reader thread to die. This will cause the pipe to be
// disconnected and closed, and a message sent (to this window)
// that the start button can be enabled again.
endReaderThread = 1;
// We check for this in the start procedure. Since the start button
// can't be enabled until the thread is about to die, we are safe
// from a race condition where the user starts two reader threads.
readerThreadCreated = false;
}
}