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

939 lines
19 KiB
C++

// Spewview: remote debug spew monitor
//
// Copyright (c) 2000 Microsoft Corp.
//
// Main dialog window
//
// 16 Mar 2000 sburns
#include "headers.hxx"
#include "MainDialog.hpp"
#include "SpewDialog.hpp"
#include "resource.h"
static const DWORD _help_map[] =
{
IDC_CLIENT_NAME, NO_HELP,
IDC_APP_NAME, NO_HELP,
IDC_GET_FLAGS, NO_HELP,
IDC_SET_FLAGS, NO_HELP,
IDC_VIEW_SPEW, NO_HELP,
IDC_FLAGS_GROUP, NO_HELP,
IDC_OUTPUT_TO_FILE, NO_HELP,
IDC_OUTPUT_TO_DEBUGGER, NO_HELP,
IDC_OUTPUT_TO_SPEWVIEW, NO_HELP,
IDC_OUTPUT_LOGS, NO_HELP,
IDC_OUTPUT_HEADER, NO_HELP,
IDC_OUTPUT_ERRORS, NO_HELP,
IDC_OUTPUT_CTORS, NO_HELP,
IDC_OUTPUT_ADDREFS, NO_HELP,
IDC_OUTPUT_FUNCCALLS, NO_HELP,
IDC_OUTPUT_TIME_OF_DAY, NO_HELP,
IDC_OUTPUT_RUN_TIME, NO_HELP,
IDC_OUTPUT_SCOPE_EXIT, NO_HELP,
IDC_FLAGS, NO_HELP,
IDC_STATUS, NO_HELP,
0, 0
};
static const DWORD ID_TO_FLAGMAP[] =
{
IDC_OUTPUT_TO_FILE, Burnslib::Log::OUTPUT_TO_FILE,
IDC_OUTPUT_TO_DEBUGGER, Burnslib::Log::OUTPUT_TO_DEBUGGER,
IDC_OUTPUT_TO_SPEWVIEW, Burnslib::Log::OUTPUT_TO_SPEWVIEW,
IDC_OUTPUT_LOGS, Burnslib::Log::OUTPUT_LOGS,
IDC_OUTPUT_HEADER, Burnslib::Log::OUTPUT_HEADER,
IDC_OUTPUT_ERRORS, Burnslib::Log::OUTPUT_ERRORS,
IDC_OUTPUT_CTORS, Burnslib::Log::OUTPUT_CTORS,
IDC_OUTPUT_ADDREFS, Burnslib::Log::OUTPUT_ADDREFS,
IDC_OUTPUT_FUNCCALLS, Burnslib::Log::OUTPUT_FUNCCALLS,
IDC_OUTPUT_TIME_OF_DAY, Burnslib::Log::OUTPUT_TIME_OF_DAY,
IDC_OUTPUT_RUN_TIME, Burnslib::Log::OUTPUT_RUN_TIME,
IDC_OUTPUT_SCOPE_EXIT, Burnslib::Log::OUTPUT_SCOPE_EXIT,
0, 0
};
MainDialog::MainDialog()
:
Dialog(IDD_MAIN, _help_map),
spewviewer(0),
setFlagsOnStart(false)
{
LOG_CTOR(MainDialog);
}
MainDialog::~MainDialog()
{
LOG_DTOR(MainDialog);
SaveUiHistory();
delete spewviewer;
spewviewer = 0;
}
void
MainDialog::SetStatusText(const String& text)
{
LOG_FUNCTION2(MainDialog::SetStatusText, text);
Win::SetDlgItemText(hwnd, IDC_STATUS, text);
}
void
MainDialog::EnableControls()
{
LOG_FUNCTION(MainDialog::EnableControls);
String c = Win::GetTrimmedDlgItemText(hwnd, IDC_CLIENT_NAME);
String a = Win::GetTrimmedDlgItemText(hwnd, IDC_APP_NAME);
bool enableButtons =
!Win::GetTrimmedDlgItemText(hwnd, IDC_CLIENT_NAME).empty()
&& !Win::GetTrimmedDlgItemText(hwnd, IDC_APP_NAME).empty();
Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_GET_FLAGS), enableButtons);
Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_SET_FLAGS), enableButtons);
Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_VIEW_SPEW), enableButtons);
Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_FLAGS_GROUP), enableButtons);
for (int i = 0; ID_TO_FLAGMAP[i]; i += 2)
{
Win::EnableWindow(
Win::GetDlgItem(hwnd, ID_TO_FLAGMAP[i]),
enableButtons);
}
}
void
MainDialog::AddToUiHistory(const String& clientName, const String& appName)
{
LOG_FUNCTION(MainDialog::AddToUiHistory);
ASSERT(!clientName.empty());
ASSERT(!appName.empty());
push_back_unique(clientNameHistory, clientName);
push_back_unique(appNameHistory, appName);
lastClientNameUsed = clientName;
lastAppNameUsed = appName;
}
// Caller must call Win::RegCloseKey(remoteHKLM)
HRESULT
MainDialog::ConnectToClientRegistry(
HKEY& remoteHKLM,
String& clientName,
String& appName)
{
LOG_FUNCTION(MainDialog::ConnectToClientRegistry);
ASSERT(!remoteHKLM);
remoteHKLM = 0;
clientName = Win::GetTrimmedDlgItemText(hwnd, IDC_CLIENT_NAME);
appName = Win::GetTrimmedDlgItemText(hwnd, IDC_APP_NAME);
if (clientName.empty() or appName.empty())
{
popup.Error(
hwnd,
L"You need to specify a client machine and application");
return E_INVALIDARG;
}
HRESULT hr = S_OK;
do
{
SetStatusText(
String::format(
L"Attempting to attach to machine %1",
clientName.c_str()));
Computer comp(clientName);
hr = comp.Refresh();
if (FAILED(hr))
{
String msg =
String::format(
L"Can't attach to client machine %1",
clientName.c_str());
SetStatusText(msg);
popup.Error(hwnd, hr, msg);
break;
}
// connect to the client machine's registry
hr =
Win::RegConnectRegistry(
comp.IsLocal() ? String() : L"\\\\" + comp.GetNetbiosName(),
HKEY_LOCAL_MACHINE,
remoteHKLM);
if (FAILED(hr))
{
String msg =
String::format(
L"Can't connect to registry of client machine %1",
clientName.c_str());
SetStatusText(msg);
popup.Error(hwnd, hr, msg);
break;
}
}
while (0);
#ifdef DBG
if (SUCCEEDED(hr))
{
ASSERT(remoteHKLM);
}
#endif
return hr;
}
DWORD
CollectFlags(HWND dialogParent)
{
LOG_FUNCTION(CollectFlags);
ASSERT(Win::IsWindow(dialogParent));
DWORD outputFlags = 0;
for (int i = 0; ID_TO_FLAGMAP[i]; i += 2)
{
if (Win::IsDlgButtonChecked(dialogParent, ID_TO_FLAGMAP[i]))
{
outputFlags |= ID_TO_FLAGMAP[i + 1];
}
}
return outputFlags;
}
void
UpdateFlagsEdit(HWND dialogParent)
{
LOG_FUNCTION(UpdateFlagsEdit);
ASSERT(Win::IsWindow(dialogParent));
DWORD flags = CollectFlags(dialogParent);
Win::SetDlgItemText(
dialogParent,
IDC_FLAGS,
String::format(L"%1!08X!", flags));
}
// Set the logging options
//
// remoteHKLM - already opened registry handle. Not closed by this
// function.
HRESULT
SetLoggingOptions(
HWND dialogParent,
HKEY remoteHKLM,
const String& clientName,
const String& appName)
{
LOG_FUNCTION(SetLoggingOptions);
ASSERT(Win::IsWindow(dialogParent));
ASSERT(remoteHKLM);
ASSERT(!clientName.empty());
ASSERT(!appName.empty());
HRESULT hr = S_OK;
do
{
String logKey = String(REG_ADMIN_RUNTIME_OPTIONS) + appName;
RegistryKey key;
hr = key.Create(remoteHKLM, logKey);
if (FAILED(hr))
{
popup.Error(
dialogParent,
hr,
String::format(
L"Can't create logging registry key %1 on client machine %2",
logKey.c_str(),
clientName.c_str()));
break;
}
DWORD outputFlags = CollectFlags(dialogParent);
hr = key.SetValue(L"LogFlags", outputFlags);
if (FAILED(hr))
{
popup.Error(
dialogParent,
hr,
String::format(
L"Can't set logging registry value on client machine %1",
clientName.c_str()));
break;
}
}
while (0);
return hr;
}
HRESULT
MainDialog::SetFlags()
{
LOG_FUNCTION(MainDialog::SetFlags);
HRESULT hr = S_OK;
HKEY remoteHKLM = 0;
String clientName;
String appName;
do
{
hr = ConnectToClientRegistry(remoteHKLM, clientName, appName);
// if that failed, the connect function will have griped to the user
// already, so just bail out here
BREAK_ON_FAILED_HRESULT(hr);
hr = SetLoggingOptions(hwnd, remoteHKLM, clientName, appName);
// ditto about griping here
BREAK_ON_FAILED_HRESULT(hr);
}
while (0);
Win::RegCloseKey(remoteHKLM);
if (SUCCEEDED(hr))
{
// Since we could successfully perform the operation, save the
// client name and app name in the ui history
AddToUiHistory(clientName, appName);
}
return hr;
}
void
MainDialog::OnSetFlagsButton()
{
LOG_FUNCTION(MainDialog::OnSetFlagsButton);
if (SUCCEEDED(SetFlags()))
{
// refresh the flags
HRESULT hr = GetFlags();
ASSERT(SUCCEEDED(hr));
SetStatusText(L"Flags set successfully.");
}
}
void
MainDialog::OnGetFlagsButton()
{
LOG_FUNCTION(MainDialog::OnGetFlagsButton);
if (SUCCEEDED(GetFlags()))
{
SetStatusText(L"Flags read successfully.");
}
}
void
MainDialog::UpdateCheckboxen(DWORD flags)
{
LOG_FUNCTION(MainDialog::UpdateCheckboxen);
for (int i = 0; ID_TO_FLAGMAP[i]; i += 2)
{
Win::CheckDlgButton(
hwnd,
ID_TO_FLAGMAP[i],
(flags & ID_TO_FLAGMAP[i + 1])
? BST_CHECKED
: BST_UNCHECKED);
}
}
void
MainDialog::ResetFlagsDisplay()
{
LOG_FUNCTION(MainDialog::ResetFlagsDisplay);
Win::SetDlgItemText(hwnd, IDC_FLAGS, L"");
Win::UpdateWindow(Win::GetDlgItem(hwnd, IDC_FLAGS));
// clear all the checkboxes
UpdateCheckboxen(0);
}
HRESULT
MainDialog::GetFlags()
{
LOG_FUNCTION(MainDialog::GetFlags);
HRESULT hr = S_OK;
HKEY remoteHKLM = 0;
String clientName;
String appName;
Win::WaitCursor wait;
do
{
ResetFlagsDisplay();
hr = ConnectToClientRegistry(remoteHKLM, clientName, appName);
// if that failed, the connect function will have griped to the user
// already, so just bail out here
BREAK_ON_FAILED_HRESULT(hr);
// Set the logging options
String logKey = String(REG_ADMIN_RUNTIME_OPTIONS) + appName;
RegistryKey key;
hr = key.Open(remoteHKLM, logKey);
if (FAILED(hr))
{
String msg =
String::format(
L"Can't open logging registry key %1 on client machine %2",
logKey.c_str(),
clientName.c_str());
SetStatusText(msg);
popup.Error(hwnd, hr, msg);
break;
}
DWORD outputFlags = 0;
hr = key.GetValue(L"LogFlags", outputFlags);
if (FAILED(hr))
{
String msg =
String::format(
L"Can't get logging registry value on client machine %1",
clientName.c_str());
SetStatusText(msg);
popup.Error(hwnd, hr, msg);
break;
}
// here, we've got the flags, so update the checkboxen
UpdateCheckboxen(outputFlags);
UpdateFlagsEdit(hwnd);
}
while (0);
Win::RegCloseKey(remoteHKLM);
if (SUCCEEDED(hr))
{
// Since we could successfully perform the operation, save the
// client name and app name in the ui history
AddToUiHistory(clientName, appName);
}
return hr;
}
HRESULT
MainDialog::SetClientConfiguration()
{
LOG_FUNCTION(MainDialog::SetClientConfiguration);
HRESULT hr = S_OK;
HKEY remoteHKLM = 0;
String clientName;
String appName;
Win::WaitCursor wait;
do
{
hr = ConnectToClientRegistry(remoteHKLM, clientName, appName);
// if that failed, the connect function will have griped to the user
// already, so just bail out here
BREAK_ON_FAILED_HRESULT(hr);
// create the spewview key with the name of the server (this machine)
RegistryKey key;
hr =
key.Create(
remoteHKLM,
SPEWVIEW_KEY_NAME + appName,
REG_OPTION_VOLATILE);
if (FAILED(hr))
{
popup.Error(
hwnd,
hr,
String::format(
L"Can't create spewview registry key on client machine %1",
clientName.c_str()));
break;
}
hr =
key.SetValue(
L"Server",
Win::GetComputerNameEx(ComputerNameNetBIOS));
if (FAILED(hr))
{
popup.Error(
hwnd,
hr,
String::format(
L"Can't set spewview server registry value on client machine %1",
clientName.c_str()));
break;
}
if (setFlagsOnStart)
{
hr = SetLoggingOptions(hwnd, remoteHKLM, clientName, appName);
// if that failed, the function will have griped to the user already,
// so just bail out here
BREAK_ON_FAILED_HRESULT(hr);
}
}
while (0);
Win::RegCloseKey(remoteHKLM);
if (SUCCEEDED(hr))
{
// Since we could successfully perform the operation, save the
// client name and app name in the ui history
AddToUiHistory(clientName, appName);
}
return hr;
}
void
MainDialog::OnStartButton()
{
LOG_FUNCTION(MainDialog::OnStartButton);
HRESULT hr = S_OK;
do
{
if (spewviewer)
{
popup.Error(
hwnd,
L"Spew Viewing has already commenced.");
break;
}
String clientName = Win::GetTrimmedDlgItemText(hwnd, IDC_CLIENT_NAME);
String appName = Win::GetTrimmedDlgItemText(hwnd, IDC_APP_NAME);
if (clientName.empty() or appName.empty())
{
popup.Error(
hwnd,
L"You need to specify a client machine and application");
break;
}
if (!setFlagsOnStart)
{
GetFlags();
}
// configure the client
hr = SetClientConfiguration();
// if that call failed, it will have griped at the user.
BREAK_ON_FAILED_HRESULT(hr);
// deleted either in dtor or in WM_KILL_SPEWVIEWER handler
spewviewer = new SpewDialog(clientName, appName);
spewviewer->ModelessExecute(hwnd);
}
while (0);
}
bool
MainDialog::OnCommand(
HWND windowFrom,
unsigned controlIDFrom,
unsigned code)
{
// LOG_FUNCTION(MainDialog::OnCommand);
switch (controlIDFrom)
{
case IDC_VIEW_SPEW:
{
if (code == BN_CLICKED)
{
OnStartButton();
return true;
}
break;
}
case IDC_GET_FLAGS:
{
if (code == BN_CLICKED)
{
OnGetFlagsButton();
return true;
}
break;
}
case IDC_SET_FLAGS:
{
if (code == BN_CLICKED)
{
OnSetFlagsButton();
return true;
}
break;
}
case IDCANCEL:
{
if (code == BN_CLICKED)
{
// kill the spew window...
Win::EndDialog(hwnd, 0);
return true;
}
break;
}
case IDC_CLIENT_NAME:
case IDC_APP_NAME:
{
if (code == CBN_EDITCHANGE)
{
EnableControls();
}
if (code == CBN_CLOSEUP)
{
// move the list box selection into the combo box edit control
Win::SetWindowText(
windowFrom,
Win::ComboBox_GetCurText(windowFrom));
EnableControls();
}
break;
}
case IDC_OUTPUT_TO_FILE:
case IDC_OUTPUT_TO_DEBUGGER:
case IDC_OUTPUT_TO_SPEWVIEW:
case IDC_OUTPUT_LOGS:
case IDC_OUTPUT_HEADER:
case IDC_OUTPUT_ERRORS:
case IDC_OUTPUT_CTORS:
case IDC_OUTPUT_ADDREFS:
case IDC_OUTPUT_FUNCCALLS:
case IDC_OUTPUT_TIME_OF_DAY:
case IDC_OUTPUT_RUN_TIME:
case IDC_OUTPUT_SCOPE_EXIT:
{
if (code == BN_CLICKED)
{
UpdateFlagsEdit(hwnd);
setFlagsOnStart = true;
}
break;
}
case IDC_FLAGS:
{
switch (code)
{
case EN_CHANGE:
{
setFlagsOnStart = true;
// update the display
String text = Win::GetWindowText(windowFrom);
DWORD flags = 0;
text.convert(flags, 16);
UpdateCheckboxen(flags);
break;
}
case EN_UPDATE:
{
}
default:
{
// do nothing
break;
}
break;
}
}
default:
{
// do nothing
}
}
return false;
}
void
AddLastUsedNameToCombo(
HWND combo,
const StringList& historyList,
const String& lastNameUsed)
{
typedef std::binder1st<String::EqualIgnoreCase> FindIfPredicate;
if (!lastNameUsed.empty())
{
if (
std::find_if(
historyList.begin(),
historyList.end(),
FindIfPredicate(String::EqualIgnoreCase(), lastNameUsed))
== historyList.end() )
{
// last name used not present in history list, so add it
Win::ComboBox_AddString(combo, lastNameUsed);
}
Win::ComboBox_SelectString(combo, lastNameUsed);
}
}
void
MainDialog::OnInit()
{
LOG_FUNCTION(MainDialog::OnInit);
LoadUiHistory();
// Load the client and app name combo boxes with the historical values
HWND clientCombo = Win::GetDlgItem(hwnd, IDC_CLIENT_NAME);
Win::ComboBox_AddStrings(
clientCombo,
clientNameHistory.begin(),
clientNameHistory.end());
HWND appCombo = Win::GetDlgItem(hwnd, IDC_APP_NAME);
Win::ComboBox_AddStrings(
appCombo,
appNameHistory.begin(),
appNameHistory.end());
AddLastUsedNameToCombo(clientCombo, clientNameHistory, lastClientNameUsed);
AddLastUsedNameToCombo(appCombo, appNameHistory, lastAppNameUsed);
// Limit to number of hex digits in a DWORD
Win::Edit_LimitText(Win::GetDlgItem(hwnd, IDC_FLAGS), 8);
SetStatusText(L"");
ResetFlagsDisplay();
EnableControls();
}
void
MainDialog::LoadUiHistory()
{
LOG_FUNCTION(MainDialog::LoadUiHistory);
HRESULT hr = S_OK;
do
{
RegistryKey key;
hr = key.Open(HKEY_LOCAL_MACHINE, SPEWVIEW_KEY_NAME);
BREAK_ON_FAILED_HRESULT(hr);
hr =
key.GetValue(
L"ClientNameHistory",
std::back_inserter(clientNameHistory));
LOG_HRESULT(hr);
// don't break on failure, try to read the app name history too.
hr =
key.GetValue(
L"AppNameHistory",
std::back_inserter(appNameHistory));
LOG_HRESULT(hr);
// don't break on failure, try to read the last names used, too.
hr = key.GetValue(L"LastClientNameUsed", lastClientNameUsed);
LOG_HRESULT(hr);
hr = key.GetValue(L"LastAppNameUsed", lastAppNameUsed);
LOG_HRESULT(hr);
}
while (0);
}
void
MainDialog::SaveUiHistory()
{
LOG_FUNCTION(MainDialog::SaveUiHistory);
HRESULT hr = S_OK;
do
{
RegistryKey key;
hr = key.Create(HKEY_LOCAL_MACHINE, SPEWVIEW_KEY_NAME);
BREAK_ON_FAILED_HRESULT(hr);
hr =
key.SetValue(
L"ClientNameHistory",
clientNameHistory.begin(),
clientNameHistory.end());
LOG_HRESULT(hr);
// don't break on failure, try to write the app name history too.
hr =
key.SetValue(
L"AppNameHistory",
appNameHistory.begin(),
appNameHistory.end());
LOG_HRESULT(hr);
// don't break on failure, try to write the last names used, too.
hr = key.SetValue(L"LastClientNameUsed", lastClientNameUsed);
LOG_HRESULT(hr);
hr = key.SetValue(L"LastAppNameUsed", lastAppNameUsed);
LOG_HRESULT(hr);
}
while (0);
}
bool
MainDialog::OnMessage(
UINT message,
WPARAM /* wparam */ ,
LPARAM /* lparam */ )
{
switch (message)
{
case WM_KILL_SPEWVIEWER:
{
delete spewviewer;
spewviewer = 0;
return true;
}
default:
{
// do nothing
break;
}
}
return false;
}