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.
 
 
 
 
 
 

3806 lines
110 KiB

//////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
// Copyright (c) 2002 OSR Open Systems Resources, Inc.
//
// DisplayDlg.cpp : implementation file
//////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <tchar.h>
#include <wmistr.h>
#include <initguid.h>
#include <ks.h>
extern "C" {
#include <evntrace.h>
}
#include <traceprt.h>
#include "TraceView.h"
#include "logsession.h"
#include "DockDialogBar.h"
#include "DisplayDlg.h"
#include "utils.h"
// GLOBALS
//
// global event callbacks
// We need these because there is no context we can
// pass into the trace event callback routines, thus
// we must have a unique callback for each instance
// of this class. We can't use a global hash like
// we are doing for the buffer callbacks, as we don't
// get any information in the EVENT_TRACE struct that
// allows us to lookup a value. This struct is filled
// in by the call to FormatTraceEvents, and we are
// supposed to treat this struct as opaque. We must
// have a unique EventListHead for the call to
// FormatTraceEvents, so we need these separate callbacks.
// Yuck!
//
PEVENT_CALLBACK g_pDumpEvent[MAX_LOG_SESSIONS];
//
// Global hash table used in the event callbacks
// to get the proper CDisplayDlg instance.
//
CMapWordToPtr g_displayIDToDisplayDlgHash(16);
//
// Global hash table used in the buffer callback
// to get the proper CDisplayDlg instance.
//
CMapStringToPtr g_loggerNameToDisplayDlgHash(16);
//
// Yet another global hash table, this one is used
// to prevent multiple sessions from starting using
// the same format GUIDs. Format info as it turns out
// is stored in a global hash table in traceprt.dll.
// If multiple sessions in the same process attempt
// to use the same format GUID, only one entry is
// entered into the traceprt hash as expected. But,
// the hash entries are removed when a session ends.
// So, if multiple sessions in the same process were
// use the same format GUID, as soon as one of those
// sessions ended, the other sessions will lose their
// hash entries.
//
CMapStringToPtr g_formatInfoHash(16);
//
// Synchronization event for GetTraceGuids, FormatTraceEvent,
// and CleanupEventListHead in traceprt.dll. These are not
// inherently thread safe.
//
HANDLE g_hGetTraceEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
//
// Buffer callback prototype
//
ULONG WINAPI BufferCallback(PEVENT_TRACE_LOGFILE Buffer);
//
// Memory Tracking
//
BOOLEAN RecoveringMemory = FALSE;
LONG MaxTraceEntries = 50000;
// CDisplayDlg dialog
IMPLEMENT_DYNAMIC(CDisplayDlg, CDialog)
CDisplayDlg::CDisplayDlg(CWnd* pParent, LONG DisplayID)
: CDialog(CDisplayDlg::IDD, pParent)
{
ASSERT(DisplayID < MAX_LOG_SESSIONS);
//
// Get a handle to the main frame
//
m_hMainWnd = pParent->GetSafeHwnd();
//
// Save the ID for this DisplayDlg
//
m_displayID = DisplayID;
//
// Setup the default flags and names for the listing and summary files
//
m_bWriteListingFile = FALSE;
m_bWriteSummaryFile = FALSE;
m_listingFileName.Format(_T("Output%d.out"), m_displayID);
m_summaryFileName.Format(_T("Summary%d.sum"), m_displayID);
//
// initialize the column names
//
m_columnName.Add("Name");
m_columnName.Add("File Name");
m_columnName.Add("Line#");
m_columnName.Add("Func Name");
m_columnName.Add("Process ID");
m_columnName.Add("Thread ID");
m_columnName.Add("CPU#");
m_columnName.Add("Sequence#");
m_columnName.Add("System Time");
m_columnName.Add("Kernel Time");
m_columnName.Add("User Time");
m_columnName.Add("Indent");
m_columnName.Add("Flags Name");
m_columnName.Add("Level Name");
m_columnName.Add("Component Name");
m_columnName.Add("SubComponent Name");
m_columnName.Add("Message");
//
// Set the initial column widths
//
for(LONG ii = 0; ii < MaxTraceSessionOptions; ii++) {
m_columnWidth[ii] = 100;
}
//
// Set the default display flags
//
m_displayFlags = TRACEOUTPUT_DISPLAY_PROVIDERNAME |
TRACEOUTPUT_DISPLAY_MESSAGE |
TRACEOUTPUT_DISPLAY_FILENAME |
TRACEOUTPUT_DISPLAY_LINENUMBER |
TRACEOUTPUT_DISPLAY_FUNCTIONNAME |
TRACEOUTPUT_DISPLAY_PROCESSID |
TRACEOUTPUT_DISPLAY_THREADID |
TRACEOUTPUT_DISPLAY_CPUNUMBER |
TRACEOUTPUT_DISPLAY_SEQNUMBER |
TRACEOUTPUT_DISPLAY_SYSTEMTIME;
//
// setup the lookup tables for the column positions
//
for(LONG ii = 0; ii < MaxTraceSessionOptions; ii++) {
//
// This lookup table allows a retrieval of the current
// position of a given column like m_retrievalArray[Flags]
// will return the correct column value for the Flags
// column
//
m_retrievalArray[ii] = ii;
//
// This lookup table allows correct placement of
// a column being added. So, if the Flags column
// needed to be inserted, then m_insertionArray[Flags]
// would give the correct insertion column value
//
m_insertionArray[ii] = ii;
}
//
// initialize the dock dialog bar pointer
//
m_pDockDialogBar = NULL;
//
// Show latest event trace entry
//
m_bShowLatest = TRUE;
//
// Setup the sort related compare function table
// There are two functions for each column, an
// ascending compare and a descending compare.
//
m_traceSortRoutine[ProviderName] = CompareOnName;
m_traceSortRoutine[Message] = CompareOnMessage;
m_traceSortRoutine[FileName] = CompareOnFileName;
m_traceSortRoutine[LineNumber] = CompareOnLineNumber;
m_traceSortRoutine[FunctionName] = CompareOnFunctionName;
m_traceSortRoutine[ProcessId] = CompareOnProcessId;
m_traceSortRoutine[ThreadId] = CompareOnThreadId;
m_traceSortRoutine[CpuNumber] = CompareOnCpuNumber;
m_traceSortRoutine[SeqNumber] = CompareOnSeqNumber;
m_traceSortRoutine[SystemTime] = CompareOnSystemTime;
m_traceSortRoutine[KernelTime] = CompareOnKernelTime;
m_traceSortRoutine[UserTime] = CompareOnUserTime;
m_traceSortRoutine[Indent] = CompareOnIndent;
m_traceSortRoutine[FlagsName] = CompareOnFlagsName;
m_traceSortRoutine[LevelName] = CompareOnLevelName;
m_traceSortRoutine[ComponentName] = CompareOnComponentName;
m_traceSortRoutine[SubComponentName]= CompareOnSubComponentName;
m_traceReverseSortRoutine[ProviderName] = ReverseCompareOnName;
m_traceReverseSortRoutine[Message] = ReverseCompareOnMessage;
m_traceReverseSortRoutine[FileName] = ReverseCompareOnFileName;
m_traceReverseSortRoutine[LineNumber] = ReverseCompareOnLineNumber;
m_traceReverseSortRoutine[FunctionName] = ReverseCompareOnFunctionName;
m_traceReverseSortRoutine[ProcessId] = ReverseCompareOnProcessId;
m_traceReverseSortRoutine[ThreadId] = ReverseCompareOnThreadId;
m_traceReverseSortRoutine[CpuNumber] = ReverseCompareOnCpuNumber;
m_traceReverseSortRoutine[SeqNumber] = ReverseCompareOnSeqNumber;
m_traceReverseSortRoutine[SystemTime] = ReverseCompareOnSystemTime;
m_traceReverseSortRoutine[KernelTime] = ReverseCompareOnKernelTime;
m_traceReverseSortRoutine[UserTime] = ReverseCompareOnUserTime;
m_traceReverseSortRoutine[Indent] = ReverseCompareOnIndent;
m_traceReverseSortRoutine[FlagsName] = ReverseCompareOnFlagsName;
m_traceReverseSortRoutine[LevelName] = ReverseCompareOnLevelName;
m_traceReverseSortRoutine[ComponentName] = ReverseCompareOnComponentName;
m_traceReverseSortRoutine[SubComponentName]= ReverseCompareOnSubComponentName;
//
// Zero our column array buffer
//
memset(m_columnArray, 0, sizeof(int) * MaxTraceSessionOptions);
//
// Setup the array of event handler pointers
//
g_pDumpEvent[0] = DumpEvent0;
g_pDumpEvent[1] = DumpEvent1;
g_pDumpEvent[2] = DumpEvent2;
g_pDumpEvent[3] = DumpEvent3;
g_pDumpEvent[4] = DumpEvent4;
g_pDumpEvent[5] = DumpEvent5;
g_pDumpEvent[6] = DumpEvent6;
g_pDumpEvent[7] = DumpEvent7;
g_pDumpEvent[8] = DumpEvent8;
g_pDumpEvent[9] = DumpEvent9;
g_pDumpEvent[10] = DumpEvent10;
g_pDumpEvent[11] = DumpEvent11;
g_pDumpEvent[12] = DumpEvent12;
g_pDumpEvent[13] = DumpEvent13;
g_pDumpEvent[14] = DumpEvent14;
g_pDumpEvent[15] = DumpEvent15;
g_pDumpEvent[16] = DumpEvent16;
g_pDumpEvent[17] = DumpEvent17;
g_pDumpEvent[18] = DumpEvent18;
g_pDumpEvent[19] = DumpEvent19;
g_pDumpEvent[20] = DumpEvent20;
g_pDumpEvent[21] = DumpEvent21;
g_pDumpEvent[22] = DumpEvent22;
g_pDumpEvent[23] = DumpEvent23;
g_pDumpEvent[24] = DumpEvent24;
g_pDumpEvent[25] = DumpEvent25;
g_pDumpEvent[26] = DumpEvent26;
g_pDumpEvent[27] = DumpEvent27;
g_pDumpEvent[28] = DumpEvent28;
g_pDumpEvent[29] = DumpEvent29;
g_pDumpEvent[30] = DumpEvent30;
g_pDumpEvent[31] = DumpEvent31;
g_pDumpEvent[32] = DumpEvent32;
g_pDumpEvent[33] = DumpEvent33;
g_pDumpEvent[34] = DumpEvent34;
g_pDumpEvent[35] = DumpEvent35;
g_pDumpEvent[36] = DumpEvent36;
g_pDumpEvent[37] = DumpEvent37;
g_pDumpEvent[38] = DumpEvent38;
g_pDumpEvent[39] = DumpEvent39;
g_pDumpEvent[40] = DumpEvent40;
g_pDumpEvent[41] = DumpEvent41;
g_pDumpEvent[42] = DumpEvent42;
g_pDumpEvent[43] = DumpEvent43;
g_pDumpEvent[44] = DumpEvent44;
g_pDumpEvent[45] = DumpEvent45;
g_pDumpEvent[46] = DumpEvent46;
g_pDumpEvent[47] = DumpEvent47;
g_pDumpEvent[48] = DumpEvent48;
g_pDumpEvent[49] = DumpEvent49;
g_pDumpEvent[50] = DumpEvent50;
g_pDumpEvent[51] = DumpEvent51;
g_pDumpEvent[52] = DumpEvent52;
g_pDumpEvent[53] = DumpEvent53;
g_pDumpEvent[54] = DumpEvent54;
g_pDumpEvent[55] = DumpEvent55;
g_pDumpEvent[56] = DumpEvent56;
g_pDumpEvent[57] = DumpEvent57;
g_pDumpEvent[58] = DumpEvent58;
g_pDumpEvent[59] = DumpEvent59;
g_pDumpEvent[60] = DumpEvent60;
g_pDumpEvent[61] = DumpEvent61;
g_pDumpEvent[62] = DumpEvent62;
g_pDumpEvent[63] = DumpEvent63;
//
// Put this session in the global hash table by display ID
//
g_displayIDToDisplayDlgHash.SetAt((WORD)m_displayID, this);
//
// Set our event callback
//
m_pEventCallback = g_pDumpEvent[m_displayID];
//
// Set our event list head to NULL
//
m_pEventListHead = NULL;
//
// initialize the group flags
//
m_bGroupActive = FALSE;
m_bGroupInActive = FALSE;
//
// Initialize the end trace event
//
m_hEndTraceEvent = NULL;
//
// Initialize the last sorted column value to be
// an invalid column so as to not sort, we track
// the column so sorts can be reversed.
//
m_lastSorted = MaxTraceSessionOptions;
//
// Sort order for trace array, TRUE == descending, FALSE == ascending
//
m_bOrder = TRUE;
//
// Initialize handles
//
m_hRealTimeOutputThread = INVALID_HANDLE_VALUE;
m_hRealTimeProcessingDoneEvent = NULL;
m_hRealTimeProcessingStartEvent = NULL;
m_hRealTimeTerminationEvent = NULL;
m_hTraceEventMutex = NULL;
m_hSessionArrayMutex = NULL;
}
CDisplayDlg::~CDisplayDlg()
{
ULONG exitCode = STILL_ACTIVE;
CTraceViewApp *pMainWnd;
//
// Clear the trace log
//
//
// Get a pointer to the app
//
pMainWnd = (CTraceViewApp *)AfxGetApp();
//
// Get our trace event array protection
//
WaitForSingleObject(m_hTraceEventMutex,INFINITE);
//
// Send all elements to be freed
//
int elCount;
elCount = (int)m_traceArray.GetSize();
while (elCount > 0 ) {
delete m_traceArray.GetAt( --elCount );
}
//
// Remove the elements from the array
//
m_traceArray.RemoveAll();
//
// Release our trace event array protection
//
ReleaseMutex(m_hTraceEventMutex);
//
// empty the list control
//
m_displayCtrl.DeleteAllItems();
//
// Reset the flag
//
exitCode = STILL_ACTIVE;
//
// Terminate the real time thread
//
SetEvent(m_hRealTimeTerminationEvent);
//
// Wait on the real time thread to exit
//
for(LONG ii = 0; (ii < 200) && (exitCode == STILL_ACTIVE); ii++) {
if(0 == GetExitCodeThread(m_hRealTimeOutputThread, &exitCode)) {
break;
}
Sleep(100);
//
// set the event again just in case
//
SetEvent(m_hRealTimeTerminationEvent);
}
//
// We waited 20 seconds and the thread didn't die, so kill it
//
if(exitCode == STILL_ACTIVE) {
TerminateThread(m_hRealTimeOutputThread, 0);
}
m_hRealTimeOutputThread = INVALID_HANDLE_VALUE;
//
// Pull this DisplayDlg out of the global hash table
//
g_displayIDToDisplayDlgHash.RemoveKey((WORD)m_displayID);
//
// The dialog bar should be deleted after this object,
// but this pointer better be NULL when we are deleted
//
ASSERT(NULL == m_pDockDialogBar);
//
// Close any open handles
//
if(m_hRealTimeProcessingDoneEvent != NULL) {
CloseHandle(m_hRealTimeProcessingDoneEvent);
}
if(m_hRealTimeProcessingStartEvent != NULL) {
CloseHandle(m_hRealTimeProcessingStartEvent);
}
if(m_hRealTimeTerminationEvent != NULL) {
CloseHandle(m_hRealTimeTerminationEvent);
}
if(m_hTraceEventMutex != NULL) {
CloseHandle(m_hTraceEventMutex);
}
if(m_hSessionArrayMutex != NULL) {
CloseHandle(m_hSessionArrayMutex);
}
}
void CDisplayDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CDisplayDlg, CDialog)
//{{AFX_MSG_MAP(CDisplayDlg)
ON_MESSAGE(WM_USER_TRACE_DONE, OnTraceDone)
ON_MESSAGE(WM_USER_AUTOSIZECOLUMNS, AutoSizeColumns)
ON_WM_NCCALCSIZE()
ON_WM_SIZE()
ON_WM_TIMER()
ON_WM_INITMENUPOPUP()
ON_NOTIFY(LVN_GETDISPINFO, IDC_DISPLAY_LIST, OnGetDispInfo)
ON_NOTIFY(NM_CLICK, IDC_DISPLAY_LIST, OnNMClickDisplayList)
ON_NOTIFY(NM_RCLICK, IDC_DISPLAY_LIST, OnNMRClickDisplayList)
ON_NOTIFY(LVN_BEGINSCROLL, IDC_DISPLAY_LIST, OnLvnBeginScrollDisplayList)
ON_NOTIFY(HDN_ITEMCLICK, 0, OnDoSort)
ON_COMMAND(ID__AUTOSIZECOLUMNS, AutoSizeColumns)
ON_COMMAND(ID__CLEARDISPLAY, OnClearDisplay)
ON_COMMAND(ID__NAME, OnNameDisplayColumnCheck)
ON_COMMAND(ID__MESSAGE, OnMessageDisplayColumnCheck)
ON_COMMAND(ID__FILENAME, OnFileNameDisplayColumnCheck)
ON_COMMAND(ID__LINENUMBER, OnLineNumberDisplayColumnCheck)
ON_COMMAND(ID__FUNCTIONNAME, OnFunctionNameDisplayColumnCheck)
ON_COMMAND(ID__PROCESSID, OnProcessIDDisplayColumnCheck)
ON_COMMAND(ID__THREADID, OnThreadIDDisplayColumnCheck)
ON_COMMAND(ID__CPUNUMBER, OnCpuNumberDisplayColumnCheck)
ON_COMMAND(ID__SEQUENCENUMBER, OnSeqNumberDisplayColumnCheck)
ON_COMMAND(ID__SYSTEMTIME, OnSystemTimeDisplayColumnCheck)
ON_COMMAND(ID__KERNELTIME, OnKernelTimeDisplayColumnCheck)
ON_COMMAND(ID__USERTIME, OnUserTimeDisplayColumnCheck)
ON_COMMAND(ID__INDENT, OnIndentDisplayColumnCheck)
ON_COMMAND(ID__FLAGSNAME, OnFlagsNameDisplayColumnCheck)
ON_COMMAND(ID__LEVELNAME, OnLevelNameDisplayColumnCheck)
ON_COMMAND(ID__COMPONENTNAME, OnComponentNameDisplayColumnCheck)
ON_COMMAND(ID__SUBCOMPONENTNAME, OnSubComponentNameDisplayColumnCheck)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////////
// CDisplayDlg message handlers
BOOL CDisplayDlg::OnInitDialog()
{
RECT rc;
RECT parentRC;
BOOL retVal;
CString str;
retVal = CDialog::OnInitDialog();
//
// Setup the protection for our trace event array
//
m_hTraceEventMutex = CreateMutex(NULL,TRUE,NULL);
if(m_hTraceEventMutex == NULL) {
DWORD error = GetLastError();
str.Format(_T("CreateMutex Error %d %x"),error,error);
AfxMessageBox(str);
return FALSE;
}
ReleaseMutex(m_hTraceEventMutex);
//
// Setup the protection for our log session array
//
m_hSessionArrayMutex = CreateMutex(NULL,TRUE,NULL);
if(m_hSessionArrayMutex == NULL) {
DWORD error = GetLastError();
str.Format(_T("CreateMutex Error %d %x"),error,error);
AfxMessageBox(str);
return FALSE;
}
ReleaseMutex(m_hSessionArrayMutex);
//
// Create the events for the real time thread operation
//
m_hRealTimeTerminationEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if(NULL == m_hRealTimeTerminationEvent) {
DWORD error = GetLastError();
str.Format(_T("CreateEvent Error %d %x"),error,error);
AfxMessageBox(str);
return FALSE;
}
m_hRealTimeProcessingStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if(NULL == m_hRealTimeProcessingStartEvent) {
DWORD error = GetLastError();
str.Format(_T("CreateEvent Error %d %x"),error,error);
AfxMessageBox(str);
return FALSE;
}
m_hRealTimeProcessingDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if(NULL == m_hRealTimeProcessingDoneEvent) {
DWORD error = GetLastError();
str.Format(_T("CreateEvent Error %d %x"),error,error);
AfxMessageBox(str);
return FALSE;
}
//
// spawn a thread to handle real time events
//
m_pRealTimeOutputThread = AfxBeginThread((AFX_THREADPROC)RealTimeEventThread,
this,
THREAD_PRIORITY_LOWEST,
0,
CREATE_SUSPENDED);
//
// save the thread handle
//
DuplicateHandle(GetCurrentProcess(),
m_pRealTimeOutputThread->m_hThread,
GetCurrentProcess(),
&m_hRealTimeOutputThread,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
//
// start the thread
//
ResumeThread(m_pRealTimeOutputThread->m_hThread);
//
// get the parent dimensions
//
GetParent()->GetParent()->GetClientRect(&parentRC);
//
// get the dialog dimensions
//
GetWindowRect(&rc);
//
// adjust the list control dimensions
//
rc.right = parentRC.right - parentRC.left - 24;
rc.bottom = rc.bottom - rc.top;
rc.left = 0;
rc.top = 0;
//
// Create the list control
//
if(!m_displayCtrl.Create(WS_CHILD|WS_VISIBLE|WS_BORDER|LVS_REPORT|LVS_OWNERDATA,
rc,
this,
IDC_DISPLAY_LIST))
{
TRACE(_T("Failed to create logger list control\n"));
return FALSE;
}
return retVal;
}
void CDisplayDlg::OnNcPaint()
{
CRect pRect;
GetClientRect(&pRect);
InvalidateRect(&pRect, TRUE);
}
VOID CDisplayDlg::SetDisplayFlags(LONG DisplayFlags)
{
LONG addDisplayFlags = ~m_displayFlags & DisplayFlags;
LONG removeDisplayFlags = m_displayFlags & ~DisplayFlags;
LONG updateDisplayFlags = m_displayFlags & DisplayFlags;
BOOL bChanged = FALSE;
LONG ii;
LONG jj;
LONG kk;
LONG ll;
CString str;
//
// Insert any new columns and remove any uneeded
//
for(ii = 0; ii < MaxTraceSessionOptions; ii++) {
//
// add the columns
//
if(addDisplayFlags & (1 << ii)) {
//
// add the column
//
m_displayCtrl.InsertColumn(m_insertionArray[ii],
m_columnName[ii],
LVCFMT_LEFT,
m_columnWidth[ii]);
//
// update the column positions
//
for(kk = 0, ll = 0; kk < MaxTraceSessionOptions; kk++) {
m_insertionArray[kk] = ll;
if(DisplayFlags & (1 << kk)) {
m_retrievalArray[ll] = kk;
ll++;
}
}
}
//
// remove the columns
//
if(removeDisplayFlags & (1 << ii)) {
//
// delete the column
//
m_displayCtrl.DeleteColumn(m_insertionArray[ii]);
//
// update the column positions
//
for(kk = 0, ll = 0; kk < MaxTraceSessionOptions; kk++) {
m_insertionArray[kk] = ll;
if(DisplayFlags & (1 << kk)) {
m_retrievalArray[ll] = kk;
ll++;
}
}
}
}
//
// Save the new display flags
//
m_displayFlags = DisplayFlags;
//
// Save the new column order array
//
memset(m_columnArray, 0, sizeof(int) * MaxTraceSessionOptions);
m_displayCtrl.GetColumnOrderArray(m_columnArray);
}
VOID CDisplayDlg::AddSession(CLogSession *pLogSession)
{
ULONG flags;
//
// Get the array protection
//
WaitForSingleObject(m_hSessionArrayMutex, INFINITE);
//
// Add the log session to the list
//
m_sessionArray.Add(pLogSession);
//
// Is this the first session?
//
if(m_sessionArray.GetSize() == 1) {
//
// Force the columns to get updated for first time
//
flags = GetDisplayFlags();
m_displayFlags = 0;
SetDisplayFlags(flags);
//
// Fix the widths of the columns
//
AutoSizeColumns();
}
//
// Release the array protection
//
ReleaseMutex(m_hSessionArrayMutex);
}
VOID CDisplayDlg::RemoveSession(CLogSession *pLogSession)
{
LONG traceDisplayFlags;
PVOID pHashEntry;
CString hashEntryKey;
POSITION pos;
//
// Get the array protection
//
WaitForSingleObject(m_hSessionArrayMutex, INFINITE);
for(LONG ii = (LONG)m_sessionArray.GetSize() - 1; ii >= 0; ii--) {
if(pLogSession == (CLogSession *)m_sessionArray[ii]) {
m_sessionArray.RemoveAt(ii);
break;
}
}
//
// Release the array protection
//
ReleaseMutex(m_hSessionArrayMutex);
//
// Remove TMF info from our global hash, if any.
//
for(pos = g_formatInfoHash.GetStartPosition(); pos != NULL; )
{
g_formatInfoHash.GetNextAssoc(pos, hashEntryKey, pHashEntry);
if(pHashEntry == (PVOID)pLogSession) {
g_formatInfoHash.RemoveKey(hashEntryKey);
}
}
//
// Force an update of the displayed columns
//
traceDisplayFlags = GetDisplayFlags();
//
// Update the display flags and thus the display
//
SetDisplayFlags(traceDisplayFlags);
}
void CDisplayDlg::OnSize(UINT nType, int cx,int cy)
{
CRect rc;
if(!IsWindow(m_displayCtrl.GetSafeHwnd()))
{
return;
}
GetParent()->GetClientRect(&rc);
//
// reset the size of the dialog to follow the frame
//
SetWindowPos(NULL,
0,
0,
rc.right - rc.left,
rc.bottom - rc.top,
SWP_NOMOVE|SWP_SHOWWINDOW|SWP_NOZORDER);
GetClientRect(&rc);
//
// Reset the size and position of the list control in the dialog
//
m_displayCtrl.MoveWindow(rc);
}
BOOL CDisplayDlg::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message == WM_KEYDOWN)
{
//
// Ignore the escape key, otherwise
// the client area grays out on escape
//
if(pMsg->wParam == VK_ESCAPE) {
// ignore the key
return TRUE;
}
//
// For the return key, we set the list control
// to always scroll to the last item
//
if(pMsg->wParam == VK_RETURN) {
//
// Start showing the latest entries in the list
//
m_bShowLatest = TRUE;
return TRUE;
}
//
// Fix for key accelerators, otherwise they are never
// processed
//
if (AfxGetMainWnd()->PreTranslateMessage(pMsg)) {
return TRUE;
}
}
return CDialog::PreTranslateMessage(pMsg);
}
void CDisplayDlg::OnNMClickDisplayList(NMHDR *pNMHDR, LRESULT *pResult)
{
//
// Stop automatic scrolling to latest list control entry
// Hit enter to start auto scrolling again
//
m_bShowLatest = FALSE;
*pResult = 0;
}
void CDisplayDlg::OnNMRClickDisplayList(NMHDR *pNMHDR, LRESULT *pResult)
{
CString str;
DWORD position;
int listIndex;
LVHITTESTINFO lvhti;
//
// Get the position of the mouse when this
// message posted
//
position = ::GetMessagePos();
//
// Get the position in an easy to use format
//
CPoint point((int) LOWORD (position), (int)HIWORD(position));
//
// Convert to screen coordinates
//
CPoint screenPoint(point);
//
// If there are entries in the event array, then pop-up
// the menu to allow autosize columns and clear display
//
CMenu menu;
menu.LoadMenu(IDR_TRACE_SESSION_POPUP_MENU);
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, screenPoint.x, screenPoint.y, this);
*pResult = 0;
}
void CDisplayDlg::OnLvnBeginScrollDisplayList(NMHDR *pNMHDR, LRESULT *pResult)
{
//
// This feature requires Internet Explorer 5.5 or greater.
// The symbol _WIN32_IE must be >= 0x0560.
//
LPNMLVSCROLL pStateChanged = reinterpret_cast<LPNMLVSCROLL>(pNMHDR);
//
// If someone grabs the scroll handle,
// stop the list control from scrolling
//
m_bShowLatest = FALSE;
*pResult = 0;
}
void CDisplayDlg::OnGetDispInfo(NMHDR *pNMHDR, LRESULT *pResult)
{
CString str;
LV_DISPINFO *pDispInfo = (LV_DISPINFO*)pNMHDR;
LV_ITEM *pItem;
int index;
int item = 0;
int subItem = 0;
LPWSTR outStr;
CString tempString;
CString tempString2;
CTraceMessage *pTraceMessage;
if(pDispInfo == NULL) {
return;
}
//
// list control cell information
//
pItem = &pDispInfo->item;
//
// Get the cell item and subitem locators
//
item = pItem->iItem;
subItem = pItem->iSubItem;
//
// Get the string pointer we need to fill in
//
outStr = pItem->pszText;
//
// Check that this is a text buffer request
//
if(!(pItem->mask & LVIF_TEXT)) {
return;
}
//
// Make sure the text requested is text we have
//
if((m_traceArray.GetSize() == 0) ||
(item >= m_traceArray.GetSize()) ||
(item < 0)) {
_tcscpy(outStr,_T(""));
return;
}
//
// Get our trace event array protection
//
WaitForSingleObject(m_hTraceEventMutex,INFINITE);
//
// Get the message from the array
//
pTraceMessage = m_traceArray[item];
//
// Release our trace event array protection
//
ReleaseMutex(m_hTraceEventMutex);
if(NULL == pTraceMessage) {
_tcscpy(outStr,_T(""));
return;
}
CTime kernelTime(pTraceMessage->m_KernelTime);
CTime userTime(pTraceMessage->m_UserTime);
// if( (pTraceMessage->m_UserTime.dwLowDateTime != 0) && (pTraceMessage->m_UserTime.dwHighDateTime != 0) ) {
// CTime userTime1(pTraceMessage->m_UserTime);
// userTime = userTime1;
// }
//
// Copy the proper portion of the message to the out string
//
switch(m_retrievalArray[subItem]) {
case ProviderName:
_tcscpy(outStr, pTraceMessage->m_GuidName);
break;
case Message: {
_tcsncpy(outStr, pTraceMessage->m_Message, pItem->cchTextMax-4);
outStr[pItem->cchTextMax-4] = 0x00;
if( (pItem->cchTextMax-4) <=
(int)_tcslen(pTraceMessage->m_Message) ) {
_tcscat(outStr, _T("..."));
}
break;
}
case FileName:
//
// Filename and line number are combined in a single string
// so we have to parse them out. The format is generally
// something like this:
//
// myfile_c389
//
// Where myfile.c is where the event occurred and on line 389.
// This field can also signify a type of message, as in the
// Kernel Logger case, for example, so if there is no underscore
// we assume this is the case and we just print out the whole
// field.
//
if(pTraceMessage->m_GuidTypeName.Find('_') > 0) {
tempString = (LPCTSTR)pTraceMessage->m_GuidTypeName.Left(pTraceMessage->m_GuidTypeName.Find('_'));
if(tempString.IsEmpty()) {
//
// Copy the string back to the list control
//
_tcscpy(outStr, tempString);
return;
}
//
// Get the extension
//
tempString += ".";
tempString2 = (LPCTSTR)pTraceMessage->m_GuidTypeName.Right(pTraceMessage->m_GuidTypeName.GetLength() - pTraceMessage->m_GuidTypeName.Find('_') - 1);
tempString += (LPCTSTR)tempString2.Left(tempString2.FindOneOf(_T("0123456789")));
} else {
tempString = (LPCTSTR)pTraceMessage->m_GuidTypeName;
}
_tcscpy(outStr, tempString);
break;
case LineNumber:
//
// Filename and line number are combined in a single string
// so we have to parse them out. The format is generally
// something like this:
//
// myfile_c389
//
// Where myfile.c is where the event occurred and on line 389.
// This field can also signify a type of message, as in the
// Kernel Logger case, for example, so if there is no underscore
// we assume this is the case and we print nothing for the line
// number.
//
if(pTraceMessage->m_GuidTypeName.Find('_') > 0) {
tempString2 =
pTraceMessage->m_GuidTypeName.Right(pTraceMessage->m_GuidTypeName.GetLength() -
pTraceMessage->m_GuidTypeName.Find('_') - 1);
tempString2 =
tempString2.Right(tempString2.GetLength() -
tempString2.FindOneOf(_T("0123456789")));
} else {
tempString2.Empty();
}
_tcscpy(outStr, tempString2);
break;
case FunctionName:
_tcscpy(outStr, pTraceMessage->m_FunctionName);
break;
case ProcessId:
if((LONG)pTraceMessage->m_ProcessId >= 0) {
tempString.Format(_T("%d"), pTraceMessage->m_ProcessId);
} else {
tempString.Empty();
}
_tcscpy(outStr, tempString);
break;
case ThreadId:
if((LONG)pTraceMessage->m_ThreadId >= 0) {
tempString.Format(_T("%d"), pTraceMessage->m_ThreadId);
} else {
tempString.Empty();
}
_tcscpy(outStr, tempString);
break;
case CpuNumber:
if((LONG)pTraceMessage->m_CpuNumber >= 0) {
tempString.Format(_T("%d"), pTraceMessage->m_CpuNumber);
} else {
tempString.Empty();
}
_tcscpy(outStr, tempString);
break;
case SeqNumber:
if((LONG)pTraceMessage->m_SequenceNum >= 0) {
tempString.Format(_T("%d"), pTraceMessage->m_SequenceNum);
} else {
tempString.Empty();
}
_tcscpy(outStr, tempString);
break;
case SystemTime:
tempString.Format(_T("%02d\\%02d\\%4d-%02d:%02d:%02d:%02d"),
pTraceMessage->m_SystemTime.wMonth,
pTraceMessage->m_SystemTime.wDay,
pTraceMessage->m_SystemTime.wYear,
pTraceMessage->m_SystemTime.wHour,
pTraceMessage->m_SystemTime.wMinute,
pTraceMessage->m_SystemTime.wSecond,
pTraceMessage->m_SystemTime.wMilliseconds);
_tcscpy(outStr, tempString);
break;
case KernelTime:
//
// We have to do an ugly conversion here. If the year is 1969,
// then the time was blank.
//
if( (kernelTime == -1) || (kernelTime.GetYear() == 1969)) {
tempString.Format(_T(""));
} else {
tempString.Format(_T("%s-%02d:%02d:%02d"),
kernelTime.Format("%m\\%d\\%Y"),
kernelTime.GetHour() + 5,
kernelTime.GetMinute(),
kernelTime.GetSecond());
}
_tcscpy(outStr, tempString);
break;
case UserTime:
//
// We have to do an ugly conversion here. If the year is 1969 or
// 1970 then the time was blank.
//
if( (userTime == -1) || (userTime.GetYear() == 1969) || (userTime.GetYear() == 1970) ) {
tempString.Format(_T(""));
} else {
tempString.Format(_T("%s-%02d:%02d:%02d"),
userTime.Format("%m\\%d\\%Y"),
userTime.GetHour() + 5,
userTime.GetMinute(),
userTime.GetSecond());
}
_tcscpy(outStr, tempString);
break;
case Indent:
tempString.Format(_T("%d"), pTraceMessage->m_Indent);
_tcscpy(outStr, tempString);
break;
case FlagsName:
_tcscpy(outStr, pTraceMessage->m_FlagsName);
break;
case LevelName:
_tcscpy(outStr, pTraceMessage->m_LevelName);
break;
case ComponentName:
_tcscpy(outStr, pTraceMessage->m_ComponentName);
break;
case SubComponentName:
_tcscpy(outStr, pTraceMessage->m_SubComponentName);
break;
default:
//
// Default to empty string
//
_tcscpy(outStr,_T(""));
break;
}
}
void CDisplayDlg::OnClearDisplay()
{
CTraceMessage *pTraceMessage;
CTraceViewApp *pMainWnd;
//
// Clear the trace log
//
//
// Get a pointer to the main frame
//
pMainWnd = (CTraceViewApp *)AfxGetApp();
//
// Get our trace event array protection
//
WaitForSingleObject(m_hTraceEventMutex,INFINITE);
int elCount;
elCount = (int)m_traceArray.GetSize();
while (elCount > 0 ) {
delete m_traceArray.GetAt( --elCount );
}
//
// Remove the elements from the array
//
m_traceArray.RemoveAll();
//
// Release our trace event array protection
//
ReleaseMutex(m_hTraceEventMutex);
//
// Clear the list control
//
m_displayCtrl.DeleteAllItems();
//
// Reset the output to always show latest
//
m_bShowLatest = TRUE;
}
void CDisplayDlg::AutoSizeColumns()
{
LONG colWidth1;
LONG colWidth2;
LONG columnCount;
CHeaderCtrl *pHeaderCtrl;
//
// Get the list control header
//
pHeaderCtrl = m_displayCtrl.GetHeaderCtrl();
if (pHeaderCtrl != NULL)
{
//
// Get number of columns
//
columnCount = pHeaderCtrl->GetItemCount();
for(LONG ii = 0; ii < (columnCount - 1); ii++) {
//
// Get the max width of the column entries
//
m_displayCtrl.SetColumnWidth(ii, LVSCW_AUTOSIZE);
colWidth1 = m_displayCtrl.GetColumnWidth(ii);
//
// Get the width of the column header
//
m_displayCtrl.SetColumnWidth(ii, LVSCW_AUTOSIZE_USEHEADER);
colWidth2 = m_displayCtrl.GetColumnWidth(ii);
//
// Set the column width to the max of the two
// Special case the first column?? Seems to be off
// a couple of pixels
//
if(0 == ii) {
m_displayCtrl.SetColumnWidth(ii, max(colWidth1,colWidth2) + 2);
} else {
m_displayCtrl.SetColumnWidth(ii, max(colWidth1,colWidth2));
}
//
// Save the column width
//
m_columnWidth[m_retrievalArray[ii]] = m_displayCtrl.GetColumnWidth(ii);
}
//
// Special case the message column. The last column is usually
// limited to only be as wide as needed. But, if the message
// column is the last column, then use up all available space.
//
if(m_retrievalArray[columnCount - 1] != Message) {
//
// Get the column width of the last column
//
colWidth2 = m_displayCtrl.GetColumnWidth(columnCount - 1);
//
// Get the max width of the column entries for the last column
//
m_displayCtrl.SetColumnWidth(columnCount - 1, LVSCW_AUTOSIZE);
colWidth1 = m_displayCtrl.GetColumnWidth(columnCount - 1);
//
// Set the last column width to the max of the two
//
m_displayCtrl.SetColumnWidth(columnCount - 1, max(colWidth1,colWidth2));
//
// Save the column width
//
m_columnWidth[m_retrievalArray[columnCount - 1]] = m_displayCtrl.GetColumnWidth(columnCount - 1);
} else {
//
// Set the width of the column to use the remaining space
//
m_displayCtrl.SetColumnWidth(columnCount - 1,
LVSCW_AUTOSIZE_USEHEADER);
//
// Save the column width
//
m_columnWidth[m_retrievalArray[columnCount - 1]] =
m_displayCtrl.GetColumnWidth(columnCount - 1);
}
}
}
void CDisplayDlg::OnNameDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the Name flag value
//
if(flags & TRACEOUTPUT_DISPLAY_PROVIDERNAME) {
flags &= ~TRACEOUTPUT_DISPLAY_PROVIDERNAME;
} else {
flags |= TRACEOUTPUT_DISPLAY_PROVIDERNAME;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnMessageDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the Message flag value
//
if(flags & TRACEOUTPUT_DISPLAY_MESSAGE) {
flags &= ~TRACEOUTPUT_DISPLAY_MESSAGE;
} else {
flags |= TRACEOUTPUT_DISPLAY_MESSAGE;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnFileNameDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the FileName flag value
//
if(flags & TRACEOUTPUT_DISPLAY_FILENAME) {
flags &= ~TRACEOUTPUT_DISPLAY_FILENAME;
} else {
flags |= TRACEOUTPUT_DISPLAY_FILENAME;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnLineNumberDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the LineNumber flag value
//
if(flags & TRACEOUTPUT_DISPLAY_LINENUMBER) {
flags &= ~TRACEOUTPUT_DISPLAY_LINENUMBER;
} else {
flags |= TRACEOUTPUT_DISPLAY_LINENUMBER;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnFunctionNameDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the FunctionName flag value
//
if(flags & TRACEOUTPUT_DISPLAY_FUNCTIONNAME) {
flags &= ~TRACEOUTPUT_DISPLAY_FUNCTIONNAME;
} else {
flags |= TRACEOUTPUT_DISPLAY_FUNCTIONNAME;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnProcessIDDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the ProcessID flag value
//
if(flags & TRACEOUTPUT_DISPLAY_PROCESSID) {
flags &= ~TRACEOUTPUT_DISPLAY_PROCESSID;
} else {
flags |= TRACEOUTPUT_DISPLAY_PROCESSID;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnThreadIDDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the Thread ID flag value
//
if(flags & TRACEOUTPUT_DISPLAY_THREADID) {
flags &= ~TRACEOUTPUT_DISPLAY_THREADID;
} else {
flags |= TRACEOUTPUT_DISPLAY_THREADID;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnCpuNumberDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the CPU Number flag value
//
if(flags & TRACEOUTPUT_DISPLAY_CPUNUMBER) {
flags &= ~TRACEOUTPUT_DISPLAY_CPUNUMBER;
} else {
flags |= TRACEOUTPUT_DISPLAY_CPUNUMBER;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnSeqNumberDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the Sequence Number flag value
//
if(flags & TRACEOUTPUT_DISPLAY_SEQNUMBER) {
flags &= ~TRACEOUTPUT_DISPLAY_SEQNUMBER;
} else {
flags |= TRACEOUTPUT_DISPLAY_SEQNUMBER;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnSystemTimeDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the SystemTime flag value
//
if(flags & TRACEOUTPUT_DISPLAY_SYSTEMTIME) {
flags &= ~TRACEOUTPUT_DISPLAY_SYSTEMTIME;
} else {
flags |= TRACEOUTPUT_DISPLAY_SYSTEMTIME;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnKernelTimeDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the KernelTime flag value
//
if(flags & TRACEOUTPUT_DISPLAY_KERNELTIME) {
flags &= ~TRACEOUTPUT_DISPLAY_KERNELTIME;
} else {
flags |= TRACEOUTPUT_DISPLAY_KERNELTIME;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnUserTimeDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the UserTime flag value
//
if(flags & TRACEOUTPUT_DISPLAY_USERTIME) {
flags &= ~TRACEOUTPUT_DISPLAY_USERTIME;
} else {
flags |= TRACEOUTPUT_DISPLAY_USERTIME;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnIndentDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the Indent flag value
//
if(flags & TRACEOUTPUT_DISPLAY_INDENT) {
flags &= ~TRACEOUTPUT_DISPLAY_INDENT;
} else {
flags |= TRACEOUTPUT_DISPLAY_INDENT;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnFlagsNameDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the FlagsName flag value
//
if(flags & TRACEOUTPUT_DISPLAY_FLAGSNAME) {
flags &= ~TRACEOUTPUT_DISPLAY_FLAGSNAME;
} else {
flags |= TRACEOUTPUT_DISPLAY_FLAGSNAME;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnLevelNameDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the LevelName flag value
//
if(flags & TRACEOUTPUT_DISPLAY_LEVELNAME) {
flags &= ~TRACEOUTPUT_DISPLAY_LEVELNAME;
} else {
flags |= TRACEOUTPUT_DISPLAY_LEVELNAME;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnComponentNameDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the ComponentName flag value
//
if(flags & TRACEOUTPUT_DISPLAY_COMPNAME) {
flags &= ~TRACEOUTPUT_DISPLAY_COMPNAME;
} else {
flags |= TRACEOUTPUT_DISPLAY_COMPNAME;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
void CDisplayDlg::OnSubComponentNameDisplayColumnCheck()
{
LONG flags;
//
// Get the current flag values
//
flags = GetDisplayFlags();
//
// Toggle the SubComponentName flag value
//
if(flags & TRACEOUTPUT_DISPLAY_SUBCOMPNAME) {
flags &= ~TRACEOUTPUT_DISPLAY_SUBCOMPNAME;
} else {
flags |= TRACEOUTPUT_DISPLAY_SUBCOMPNAME;
}
//
// Update the flag values and thus the display
//
SetDisplayFlags(flags);
}
BOOL CDisplayDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
HD_NOTIFY *pHDN = (HD_NOTIFY*)lParam;
LPNMHDR pNH = (LPNMHDR) lParam;
//
// wParam is zero for Header ctrl
//
if(wParam == 0 && pNH->code == NM_RCLICK) {
//
// Right button was clicked on header
//
//
// Determine where the right click occurred and pop-up
// a menu there
//
CPoint pt(GetMessagePos());
CHeaderCtrl *pHeader = m_displayCtrl.GetHeaderCtrl();
pHeader->ScreenToClient(&pt);
CPoint screenPoint(GetMessagePos());
CMenu menu;
menu.LoadMenu(IDR_TRACE_DISPLAY_OPTION_POPUP_MENU);
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
screenPoint.x,
screenPoint.y,
this);
return TRUE;
} else if(wParam == 0 && pNH->code == NM_RELEASEDCAPTURE) {
//
// Column header was pressed and now released
//
POINT Point;
CHeaderCtrl *pHeader = m_displayCtrl.GetHeaderCtrl();
int columnArray[MaxTraceSessionOptions];
GetCursorPos (&Point);
ScreenToClient(&Point);
HDHITTESTINFO HitTest;
//
//Offset of right scrolling
//
HitTest.pt.x = Point.x + GetScrollPos(SB_HORZ);
HitTest.pt.y = Point.y;
//
//Send the hit test message
//
pHeader->SendMessage(HDM_HITTEST,0,(LPARAM)&HitTest);
//
// We check here if the column order changed. If so, then
// we don't want to cause a sort of the column items, the user
// had to press the column header to drag the column around.
//
memset(columnArray, 0, sizeof(int) * MaxTraceSessionOptions);
m_displayCtrl.GetColumnOrderArray(columnArray);
if(memcmp(m_columnArray, columnArray, sizeof(int) * MaxTraceSessionOptions)) {
//
// Column order changed, save the new order
//
memcpy(m_columnArray, columnArray, sizeof(int) * MaxTraceSessionOptions);
//
// Now call the default handler and return
//
return CDialog::OnNotify(wParam, lParam, pResult);
}
if(HitTest.iItem >= 0) {
//
// Now check for column resize
//
if(m_displayCtrl.GetColumnWidth(HitTest.iItem) != m_columnWidth[m_retrievalArray[HitTest.iItem]]) {
//
// Save off the new column width and don't sort the column
//
m_columnWidth[m_retrievalArray[HitTest.iItem]] = m_displayCtrl.GetColumnWidth(HitTest.iItem);
//
// Now call the default handler and return
//
return CDialog::OnNotify(wParam, lParam, pResult);
}
// //
// // Sort the table by this column's data
// //
// SortTable(HitTest.iItem);
//
// //
// // Force a redraw of the data
// //
// m_displayCtrl.RedrawItems(m_displayCtrl.GetTopIndex(),
// m_displayCtrl.GetTopIndex() + m_displayCtrl.GetCountPerPage());
//
// m_displayCtrl.UpdateWindow();
}
}
//
// Now call the default handler and return
//
return CDialog::OnNotify(wParam, lParam, pResult);
}
void CDisplayDlg::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
//
// Call the default handler
//
CDialog::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
//
// As CDisplayDlg corresponds to a non-CFrameWnd window, OF COURSE
// you have to overload this handler and explicitly set the check
// state of each item in the popup menu. It is utterly,
// absolutely, and intuitively obvious as to why this is
// necessary, thus it won't be explained here
//
//
// Trace session pop-up menu
//
//
// Disable the clear display option, if there are no
// traces displayed
//
if(m_traceArray.GetSize() == 0) {
pPopupMenu->EnableMenuItem(ID__CLEARDISPLAY, MF_GRAYED);
}
//
// Trace display option pop-up menu
//
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_PROVIDERNAME) {
pPopupMenu->CheckMenuItem(ID__NAME, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_MESSAGE) {
pPopupMenu->CheckMenuItem(ID__MESSAGE, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_FILENAME) {
pPopupMenu->CheckMenuItem(ID__FILENAME, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_LINENUMBER) {
pPopupMenu->CheckMenuItem(ID__LINENUMBER, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_FUNCTIONNAME) {
pPopupMenu->CheckMenuItem(ID__FUNCTIONNAME, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_PROCESSID) {
pPopupMenu->CheckMenuItem(ID__PROCESSID, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_THREADID) {
pPopupMenu->CheckMenuItem(ID__THREADID, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_CPUNUMBER) {
pPopupMenu->CheckMenuItem(ID__CPUNUMBER, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_SEQNUMBER) {
pPopupMenu->CheckMenuItem(ID__SEQUENCENUMBER, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_SYSTEMTIME) {
pPopupMenu->CheckMenuItem(ID__SYSTEMTIME, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_KERNELTIME) {
pPopupMenu->CheckMenuItem(ID__KERNELTIME, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_USERTIME) {
pPopupMenu->CheckMenuItem(ID__USERTIME, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_INDENT) {
pPopupMenu->CheckMenuItem(ID__INDENT, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_FLAGSNAME) {
pPopupMenu->CheckMenuItem(ID__FLAGSNAME, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_LEVELNAME) {
pPopupMenu->CheckMenuItem(ID__LEVELNAME, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_COMPNAME) {
pPopupMenu->CheckMenuItem(ID__COMPONENTNAME, MF_CHECKED);
}
if(GetDisplayFlags() & TRACEOUTPUT_DISPLAY_SUBCOMPNAME) {
pPopupMenu->CheckMenuItem(ID__SUBCOMPONENTNAME, MF_CHECKED);
}
}
void CDisplayDlg::SortTable(int Column)
{
CString str;
//
// Use qsort with the proper compare routine. We use qsort
// versus the list control's own sort functionality as its
// actually more flexible for this case. We don't have to
// parse the item data during the sorts this way. The native
// sort wouldn't buy us anything.
//
//
// Get our trace event array protection
//
WaitForSingleObject(m_hTraceEventMutex,INFINITE);
//
// Check the column to see if its in range, if not just sort
// by the last selected column
//
if(Column < MaxLogSessionOptions) {
if(m_lastSorted != m_retrievalArray[Column]) {
//
// If this column has not been used to sort the trace event
// data before, then sort ascending
//
m_bOrder = TRUE;
} else {
//
// If this column has been used before, then reverse the order
// of the sort (column header was selected again)
//
m_bOrder = (m_bOrder == TRUE ? FALSE : TRUE);
}
//
// Save the column
//
m_lastSorted = m_retrievalArray[Column];
} else if(m_lastSorted >= MaxLogSessionOptions) {
//
// Release our trace event array protection
//
ReleaseMutex(m_hTraceEventMutex);
str.Format(_T("m_lastSorted = %d"), m_lastSorted);
return;
}
//
// Determine whether to sort ascending or descending and call
// qsort with the proper callback
//
if(m_bOrder) {
qsort((PVOID)&m_traceArray[0], m_traceArray.GetSize(), sizeof(CTraceMessage *), m_traceSortRoutine[m_lastSorted]);
} else {
qsort((PVOID)&m_traceArray[0], m_traceArray.GetSize(), sizeof(CTraceMessage *), m_traceReverseSortRoutine[m_lastSorted]);
}
//
// Release our trace event array protection
//
ReleaseMutex(m_hTraceEventMutex);
}
int CDisplayDlg::CompareOnName(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage1->m_GuidName.Compare(pTraceMessage2->m_GuidName));
}
int CDisplayDlg::CompareOnMessage(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage1->m_Message.Compare(pTraceMessage2->m_Message));
}
int CDisplayDlg::CompareOnFileName(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage1->m_GuidTypeName.Compare(pTraceMessage2->m_GuidTypeName));
}
int CDisplayDlg::CompareOnLineNumber(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
CString string1;
CString string2;
DWORD val1, val2;
//
// Get Line number string for the first element
//
string1 =
pTraceMessage1->m_GuidTypeName.Right(pTraceMessage1->m_GuidTypeName.GetLength() -
pTraceMessage1->m_GuidTypeName.Find('_') - 1);
string1 =
string1.Right(string1.GetLength() -
string1.FindOneOf(_T("0123456789")));
string2 =
pTraceMessage2->m_GuidTypeName.Right(pTraceMessage2->m_GuidTypeName.GetLength() -
pTraceMessage2->m_GuidTypeName.Find('_') - 1);
//
// Get the line number string for the second element
//
string2 =
string2.Right(string2.GetLength() -
string2.FindOneOf(_T("0123456789")));
TCHAR * end;
val1 = _tcstoul(string1, &end, 10);
val2 = _tcstoul(string2, &end,10);
if(val1 == val2) {
return(0);
}
if(val1 < val2) {
return(-1);
}
return(1);
}
int CDisplayDlg::CompareOnFunctionName(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage1->m_FunctionName.Compare(pTraceMessage2->m_FunctionName));
}
int CDisplayDlg::CompareOnProcessId(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return((LONG)pTraceMessage1->m_ProcessId - (LONG)pTraceMessage2->m_ProcessId);
}
int CDisplayDlg::CompareOnThreadId(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return((LONG)pTraceMessage1->m_ThreadId - (LONG)pTraceMessage2->m_ThreadId);
}
int CDisplayDlg::CompareOnCpuNumber(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return((LONG)pTraceMessage1->m_CpuNumber - (LONG)pTraceMessage2->m_CpuNumber);
}
int CDisplayDlg::CompareOnSeqNumber(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return((LONG)pTraceMessage1->m_SequenceNum - (LONG)pTraceMessage2->m_SequenceNum);
}
int CDisplayDlg::CompareOnSystemTime(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
FILETIME timea, timeb;
BOOL res;
res = SystemTimeToFileTime(&pTraceMessage1->m_SystemTime, &timea);
res = SystemTimeToFileTime(&pTraceMessage2->m_SystemTime, &timeb);
return(CompareFileTime(&timea, &timeb));
}
int CDisplayDlg::CompareOnKernelTime(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage1->m_KernelTime - pTraceMessage2->m_KernelTime);
// return (pTraceMessage1->m_KernelTime.dwHighDateTime - pTraceMessage2->m_KernelTime.dwHighDateTime) ?
// (pTraceMessage1->m_KernelTime.dwHighDateTime - pTraceMessage2->m_KernelTime.dwHighDateTime) :
// (pTraceMessage1->m_KernelTime.dwLowDateTime - pTraceMessage2->m_KernelTime.dwLowDateTime);
}
int CDisplayDlg::CompareOnUserTime(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage1->m_UserTime - pTraceMessage2->m_UserTime);
// return (pTraceMessage1->m_UserTime.dwHighDateTime - pTraceMessage2->m_UserTime.dwHighDateTime) ?
// (pTraceMessage1->m_UserTime.dwHighDateTime - pTraceMessage2->m_UserTime.dwHighDateTime) :
// (pTraceMessage1->m_UserTime.dwLowDateTime - pTraceMessage2->m_UserTime.dwLowDateTime);
}
int CDisplayDlg::CompareOnIndent(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return((LONG)pTraceMessage1->m_Indent - (LONG)pTraceMessage2->m_Indent);
}
int CDisplayDlg::CompareOnFlagsName(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage1->m_FlagsName.Compare(pTraceMessage2->m_FlagsName));
}
int CDisplayDlg::CompareOnLevelName(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage1->m_LevelName.Compare(pTraceMessage2->m_LevelName));
}
int CDisplayDlg::CompareOnComponentName(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage1->m_ComponentName.Compare(pTraceMessage2->m_ComponentName));
}
int CDisplayDlg::CompareOnSubComponentName(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage1->m_SubComponentName.Compare(pTraceMessage2->m_SubComponentName));
}
int CDisplayDlg::ReverseCompareOnName(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage2->m_GuidName.Compare(pTraceMessage1->m_GuidName));
}
int CDisplayDlg::ReverseCompareOnMessage(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage2->m_Message.Compare(pTraceMessage1->m_Message));
}
int CDisplayDlg::ReverseCompareOnFileName(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage2->m_GuidTypeName.Compare(pTraceMessage1->m_GuidTypeName));
}
int CDisplayDlg::ReverseCompareOnLineNumber(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
CString string1;
CString string2;
DWORD val1, val2;
//
// Get Line number string for the first element
//
string1 =
pTraceMessage1->m_GuidTypeName.Right(pTraceMessage1->m_GuidTypeName.GetLength() -
pTraceMessage1->m_GuidTypeName.Find('_') - 1);
string1 =
string1.Right(string1.GetLength() -
string1.FindOneOf(_T("0123456789")));
string2 =
pTraceMessage2->m_GuidTypeName.Right(pTraceMessage2->m_GuidTypeName.GetLength() -
pTraceMessage2->m_GuidTypeName.Find('_') - 1);
//
// Get the line number string for the second element
//
string2 =
string2.Right(string2.GetLength() -
string2.FindOneOf(_T("0123456789")));
TCHAR * end;
val1 = _tcstoul(string1, &end, 10);
val2 = _tcstoul(string2, &end,10);
if(val1 == val2) {
return(0);
}
if(val1 > val2) {
return(-1);
}
return(1);
}
int CDisplayDlg::ReverseCompareOnFunctionName(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage2->m_FunctionName.Compare(pTraceMessage1->m_FunctionName));
}
int CDisplayDlg::ReverseCompareOnProcessId(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return((LONG)pTraceMessage2->m_ProcessId - (LONG)pTraceMessage1->m_ProcessId);
}
int CDisplayDlg::ReverseCompareOnThreadId(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return((LONG)pTraceMessage2->m_ThreadId - (LONG)pTraceMessage1->m_ThreadId);
}
int CDisplayDlg::ReverseCompareOnCpuNumber(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return((LONG)pTraceMessage2->m_CpuNumber - (LONG)pTraceMessage1->m_CpuNumber);
}
int CDisplayDlg::ReverseCompareOnSeqNumber(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return((LONG)pTraceMessage2->m_SequenceNum - (LONG)pTraceMessage1->m_SequenceNum);
}
int CDisplayDlg::ReverseCompareOnSystemTime(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
FILETIME timea, timeb;
BOOL res;
res = SystemTimeToFileTime(&pTraceMessage1->m_SystemTime, &timea);
res = SystemTimeToFileTime(&pTraceMessage2->m_SystemTime, &timeb);
return(CompareFileTime(&timeb, &timea));
}
int CDisplayDlg::ReverseCompareOnKernelTime(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage2->m_KernelTime - pTraceMessage1->m_KernelTime);
// return (pTraceMessage2->m_KernelTime.dwHighDateTime - pTraceMessage1->m_KernelTime.dwHighDateTime) ?
// (pTraceMessage2->m_KernelTime.dwHighDateTime - pTraceMessage1->m_KernelTime.dwHighDateTime) :
// (pTraceMessage2->m_KernelTime.dwLowDateTime - pTraceMessage1->m_KernelTime.dwLowDateTime);
}
int CDisplayDlg::ReverseCompareOnUserTime(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage2->m_UserTime - pTraceMessage1->m_UserTime);
// return (pTraceMessage2->m_UserTime.dwHighDateTime - pTraceMessage1->m_UserTime.dwHighDateTime) ?
// (pTraceMessage2->m_UserTime.dwHighDateTime - pTraceMessage1->m_UserTime.dwHighDateTime) :
// (pTraceMessage2->m_UserTime.dwLowDateTime - pTraceMessage1->m_UserTime.dwLowDateTime);
}
int CDisplayDlg::ReverseCompareOnIndent(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return((LONG)pTraceMessage2->m_Indent - (LONG)pTraceMessage1->m_Indent);
}
int CDisplayDlg::ReverseCompareOnFlagsName(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage2->m_FlagsName.Compare(pTraceMessage1->m_FlagsName));
}
int CDisplayDlg::ReverseCompareOnLevelName(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage2->m_LevelName.Compare(pTraceMessage1->m_LevelName));
}
int CDisplayDlg::ReverseCompareOnComponentName(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage2->m_ComponentName.Compare(pTraceMessage1->m_ComponentName));
}
int CDisplayDlg::ReverseCompareOnSubComponentName(const void *pMessage1, const void *pMessage2)
{
CTraceMessage *pTraceMessage1 = *(CTraceMessage **)pMessage1;
CTraceMessage *pTraceMessage2 = *(CTraceMessage **)pMessage2;
return(pTraceMessage2->m_SubComponentName.Compare(pTraceMessage1->m_SubComponentName));
}
BOOL CDisplayDlg::BeginTrace(BOOL bUseExisting)
{
CTraceSession *pTraceSession;
CLogSession *pLogSession;
LONG ii;
LONG jj;
CString str;
BOOL bGroupActive = FALSE;
//
// If the group is already started or being started, just return
// false
//
if(TRUE == SetGroupActive(TRUE)) {
return FALSE;
}
//
// The list head should always be NULL here
//
ASSERT(m_pEventListHead == NULL);
//
// Setup the event timer
//
m_eventTimer = SetTimer(1, EVENT_TIME_LIMIT, 0);
//
// zero our counts
//
m_totalBuffersRead = 0;
m_totalEventsLost = 0;
m_totalEventCount = 0;
//
// We set to use the StructuredFormat method in traceprt.dll
// and we use no prefix on the message. We have to specify no
// prefix as we cannot otherwise predictably setup the data we
// get in our event callback.
//
SetTraceFormatParameter(ParameterStructuredFormat,UlongToPtr(1));
SetTraceFormatParameter(ParameterUsePrefix,UlongToPtr(0));
//
// open the output file if writing output
//
if(m_bWriteListingFile) {
m_bListingFileOpen = FALSE;
if(!m_listingFile.Open(
m_listingFileName,
CFile::modeCreate | CFile::modeReadWrite)) {
AfxMessageBox(_T("Unable To Create Listing File"));
} else {
m_bListingFileOpen = TRUE;
}
}
//
// Get the array protection
//
WaitForSingleObject(m_hSessionArrayMutex, INFINITE);
//
// Setup the log sessions
//
for(ii = 0; ii < m_sessionArray.GetSize(); ii++) {
//
// Get the next CLogSession pointer
//
pLogSession = (CLogSession *)m_sessionArray[ii];
if(NULL == pLogSession) {
continue;
}
if(!pLogSession->BeginTrace(bUseExisting)) {
if(pLogSession->m_bTraceActive) {
//BUGBUG -- should we be doing this??
pLogSession->EndTrace();
}
continue;
}
bGroupActive = TRUE;
}
//
// Release the array protection
//
ReleaseMutex(m_hSessionArrayMutex);
//
// Show the sessions running
//
::PostMessage(m_hMainWnd, WM_USER_UPDATE_LOGSESSION_LIST, 0, 0);
//
// If none of the log sessions started successfully,
// then return FALSE
//
//BUGBUG -- maybe we want to fail if ANY of the sessions didn't start?
// Also, might need a pop-up here?
if(!bGroupActive) {
SetGroupActive(FALSE);
SetState(Stopped);
return FALSE;
}
//
// Prepare the format GUIDs and such
//
if(!SetupTraceSessions()) {
AfxMessageBox(_T("Failed To Open Handles For Any Log Sessions In Group"));
SetGroupActive(FALSE);
SetState(Stopped);
return FALSE;
}
return TRUE;
}
UINT CDisplayDlg::RealTimeEventThread(LPVOID pParam)
{
CString str;
CDisplayDlg *pDisplayDlg = (CDisplayDlg *)pParam;
CLogSession *pLogSession;
LONG status;
CTraceSession *pTraceSession;
DWORD handleIndex;
HANDLE handleArray[2];
//
// Setup the handle array, the termination event
// must always be element zero, so that it's index
// will be the index returned in case multiple
// events are set
//
handleArray[0] = pDisplayDlg->m_hRealTimeTerminationEvent;
handleArray[1] = pDisplayDlg->m_hRealTimeProcessingStartEvent;
//
// Our master control loop, loop until we get a termination event
// signal. The start event signals the loop to call ProcessTrace,
// the done event is signalled and the WM_USER_TRACE_DONE message
// posted to signal that CloseTrace was called
//
while(1) {
//
// Wait on start or termination event
//
handleIndex = WaitForMultipleObjects(2,
handleArray,
FALSE,
INFINITE) - WAIT_OBJECT_0;
//
// Did we get killed?
//
if(0 == handleIndex) {
//
// Signal that we are done.
//
::PostMessage(pDisplayDlg->GetSafeHwnd(), WM_USER_TRACE_DONE, 0, 0);
//
// Free our string buffer (threads seem to leak if this isn't done??)
//
str.Empty();
return 0;
}
//
// Reset done event for UpdateSession
//
ResetEvent(pDisplayDlg->m_hRealTimeProcessingDoneEvent);
//
// Process the trace events
//
status = ProcessTrace(pDisplayDlg->m_traceHandleArray,
pDisplayDlg->m_traceHandleCount,
NULL,
NULL);
if(ERROR_SUCCESS != status){
str.Format(_T("ProcessTrace returned error %d, GetLastError() = %d\n"), status, GetLastError());
AfxMessageBox(str);
}
//
// We are done, close the trace sessions
//
for(LONG ii = 0; ii < pDisplayDlg->m_traceHandleCount; ii++) {
status = CloseTrace(pDisplayDlg->m_traceHandleArray[ii]);
if(ERROR_SUCCESS != status){
str.Format(_T("CloseTrace returned error %d\n"), status);
AfxMessageBox(str);
}
}
//
// Set done event for UpdateSession
//
SetEvent(pDisplayDlg->m_hRealTimeProcessingDoneEvent);
//
// Indicate that we are done.
//
::PostMessage(pDisplayDlg->GetSafeHwnd(), WM_USER_TRACE_DONE, 0, 0);
}
return 0;
}
BOOL CDisplayDlg::EndTrace(HANDLE DoneEvent)
{
CString str;
CLogSession *pLogSession;
LONG ii;
BOOL bWasActive = FALSE;
BOOL bWasRealTime = FALSE;
//
// If the group is already stopped, or is stopping, just
// return FALSE.
//
if(TRUE == SetGroupInActive(TRUE)) {
return FALSE;
}
//
// Save the caller's event to be set when stopped
//
m_hEndTraceEvent = DoneEvent;
//
// Get the array protection
//
WaitForSingleObject(m_hSessionArrayMutex, INFINITE);
for(ii = 0; ii < m_sessionArray.GetSize(); ii++) {
pLogSession = (CLogSession *)m_sessionArray[ii];
if(NULL == pLogSession) {
continue;
}
//
// If the session is active, stop it
//
if(pLogSession->m_bTraceActive) {
pLogSession->EndTrace();
bWasActive = TRUE;
if(pLogSession->m_bRealTime) {
bWasRealTime = TRUE;
}
}
}
//
// Release the array protection
//
ReleaseMutex(m_hSessionArrayMutex);
if(bWasActive) {
//
// Update the log session state
//
::PostMessage(m_hMainWnd, WM_USER_UPDATE_LOGSESSION_LIST, 0, 0);
if(!bWasRealTime) {
//
// We need to explicitly call OnTraceDone here
//
OnTraceDone(NULL, NULL);
}
return TRUE;
}
return FALSE;
}
void CDisplayDlg::OnTraceDone(WPARAM wParam, LPARAM lParam)
{
CString str;
CLogSession *pLogSession = NULL;
//
// Set the group state
//
SetState(Stopping);
//
// Write the summary file if requested
//
if(m_bWriteSummaryFile) {
WriteSummaryFile();
}
//
// close the output file if opened
//
if(m_bWriteListingFile && m_bListingFileOpen) {
m_listingFile.Close();
m_bListingFileOpen = FALSE;
}
//
// Cleanup the event list
//
WaitForSingleObject(g_hGetTraceEvent, INFINITE);
//
// The event list head
//
CleanupTraceEventList(m_pEventListHead);
SetEvent(g_hGetTraceEvent);
m_pEventListHead = NULL;
//
// Remove the keys from the hash table
//
for(LONG ii = 0; ii < m_sessionArray.GetSize(); ii++) {
pLogSession = (CLogSession *)m_sessionArray[ii];
if(NULL == pLogSession) {
continue;
}
g_loggerNameToDisplayDlgHash.RemoveKey(pLogSession->GetDisplayName());
}
//
// Kill the event timer
//
KillTimer(m_eventTimer);
//
// Force one last update of the event display
//
OnTimer(1);
//
// Set the group as not active
//
SetGroupActive(FALSE);
SetGroupInActive(FALSE);
//
// Set the group state
//
SetState(Stopped);
if(m_hEndTraceEvent != NULL) {
SetEvent(m_hEndTraceEvent);
m_hEndTraceEvent = NULL;
}
return;
}
//
// Updates an active tracing session. Real-Time mode, log file name,
// flush-time, flags, and maximum buffers can be updated for active
// sessions.
//
BOOL CDisplayDlg::UpdateSession(CLogSession *pLogSession)
{
CLogSession *pLog;
PEVENT_TRACE_PROPERTIES pQueryProperties;
ULONG sizeNeeded;
LPTSTR pLoggerName;
LPTSTR pCurrentLogFileName;
LPTSTR pLogFileName;
ULONG flags;
ULONG level;
ULONG status;
CString logFileName;
CString str;
//
// setup our buffer size for the properties struct for our query
//
sizeNeeded = sizeof(EVENT_TRACE_PROPERTIES) + (2 * 1024 * sizeof(TCHAR));
//
// allocate our memory
//
pQueryProperties = (PEVENT_TRACE_PROPERTIES) new char[sizeNeeded];
if(NULL == pQueryProperties) {
return FALSE;
}
//
// zero our structures
//
memset(pQueryProperties, 0, sizeNeeded);
//
// Set the size
//
pQueryProperties->Wnode.BufferSize = sizeNeeded;
//
// Set the GUID
//
pQueryProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
//
// Set the logger name offset
//
pQueryProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
//
// Set the logger name for the query
//
pLoggerName = (LPTSTR)((char*)pQueryProperties + pQueryProperties->LoggerNameOffset);
_tcscpy(pLoggerName, pLogSession->GetDisplayName());
//
// Set the log file name offset
//
pQueryProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + (500 * sizeof(TCHAR));
//
// Get the log file name pointers
//
pCurrentLogFileName = (LPTSTR)((char*)pQueryProperties + pQueryProperties->LogFileNameOffset);
//
// Query the log session
//
status = ControlTrace(0,
pLogSession->GetDisplayName(),
pQueryProperties,
EVENT_TRACE_CONTROL_QUERY);
if(ERROR_SUCCESS != status) {
str.Format(_T("Query Failed For Log Session, %d\nSession Not Updated"), status);
AfxMessageBox(str);
}
//
// Call the log session's UpdateSession function
//
if(!pLogSession->UpdateSession(pQueryProperties)) {
delete [] pQueryProperties;
return FALSE;
}
//
// Get the array protection
//
WaitForSingleObject(m_hSessionArrayMutex, INFINITE);
for(LONG ii = 0; ii < m_sessionArray.GetSize(); ii++) {
pLog = (CLogSession *)m_sessionArray[ii];
if(pLog == pLogSession) {
continue;
}
//
// In our real-time thread we call ProcessTrace. If all sessions
// related to that call update to be non-real-time sessions, then
// ProcessTrace will exit and CloseTrace will get called. We have
// to track this and restart the real-time processing if a log session
// subsequently updates to be real-time again. So, we check here if
// any other attached sessions are real-time, and if so, we don't
// have to bother with waiting on or setting the events below.
//
if(pLog->m_bRealTime) {
delete [] pQueryProperties;
return TRUE;
}
}
//
// Release the array protection
//
ReleaseMutex(m_hSessionArrayMutex);
//
// If real-time is specified and the session was not real-time before,
// then we need to set the start event.
//
if(pLogSession->m_bRealTime &&
!(pQueryProperties->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)) {
//
// We have updated a session to be real-time and it is the only session in
// its group to be real-time. We need to restart the trace in this case
//
//
// Start the real-time thread processing again
//
BeginTrace(TRUE);
}
//
// If real-time is not set and it was before, then we need to wait on
// the real-time thread to catch the fact that the session is no longer
// tracing real time. This will cause the ProcessTrace call to
// return in the real-time thread.
//
if(!pLogSession->m_bRealTime &&
(pQueryProperties->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)) {
//
// Make sure our thread catches the stop
//
WaitForSingleObject(m_hRealTimeProcessingDoneEvent, INFINITE);
}
delete [] pQueryProperties;
return TRUE;
}
BOOL CDisplayDlg::SetupTraceSessions()
{
CTraceSession *pTraceSession;
CLogSession *pLogSession;
LONG jj;
CString str;
LPTSTR tmfFile;
PVOID pHashEntry;
//
// Initialize our handle count
//
m_traceHandleCount = 0;
//
// Get the array protection
//
WaitForSingleObject(m_hSessionArrayMutex, INFINITE);
//
// Setup the log sessions
//
for(LONG ii = 0; ii < m_sessionArray.GetSize(); ii++) {
//
// Get the next CLogSession pointer
//
pLogSession = (CLogSession *)m_sessionArray[ii];
if(NULL == pLogSession) {
continue;
}
//
// If the log session is not real-time and we are not dumping an existing
// logfile, then no need to call OpenTrace
//
if((!pLogSession->m_bRealTime) && (!pLogSession->m_bDisplayExistingLogFileOnly)) {
continue;
}
//
// zero the EVENT_TRACE_LOGFILE buffer
//
memset(&pLogSession->m_evmFile, 0, sizeof(EVENT_TRACE_LOGFILE));
//
// setup the trace parameters
//
//
// For real-time we set the logger name only, for existing logfiles we
// also set the logfile name.
//
if(pLogSession->m_bDisplayExistingLogFileOnly) {
pLogSession->m_evmFile.LogFileName = (LPTSTR)(LPCTSTR)pLogSession->m_logFileName;
pLogSession->m_evmFile.LoggerName = (LPTSTR)(LPCTSTR)pLogSession->GetDisplayName();
} else {
pLogSession->m_evmFile.LoggerName = (LPTSTR)(LPCTSTR)pLogSession->GetDisplayName();
}
pLogSession->m_evmFile.Context = NULL;
pLogSession->m_evmFile.BufferCallback = (PEVENT_TRACE_BUFFER_CALLBACK)BufferCallback;
pLogSession->m_evmFile.BuffersRead = 0;
pLogSession->m_evmFile.CurrentTime = 0;
pLogSession->m_evmFile.EventCallback = m_pEventCallback;
if(pLogSession->m_bDisplayExistingLogFileOnly) {
pLogSession->m_evmFile.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;
} else {
pLogSession->m_evmFile.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
}
//
// We call GetTraceGuids for each TMF file specified, or once if
// a TMF path is used.
//
for(jj = 0; jj < pLogSession->m_traceSessionArray.GetSize(); jj++) {
pTraceSession = (CTraceSession *)pLogSession->m_traceSessionArray[jj];
if((NULL != pTraceSession) && (0 != pTraceSession->m_tmfFile.GetSize())) {
//
// TMFs were selected get the format info from each one.
//
for(LONG kk = 0; kk < pTraceSession->m_tmfFile.GetSize(); kk++) {
//
// Make sure the format info isn't already in use
// This actually isn't foolproof, as it counts on
// no one changing the TMF filename and thus two TMFs
// with different names having the same format GUID.
//
if(g_formatInfoHash.Lookup(pTraceSession->m_tmfFile[kk].Right(40), pHashEntry)) {
//
// Need to clean out any unique entries from the hash that
// were added by this session
//
for(; kk > 0; kk--) {
g_formatInfoHash.RemoveKey(pTraceSession->m_tmfFile[kk - 1].Right(40));
}
return FALSE;
}
//
// Not there, so add it to the hash
//
g_formatInfoHash.SetAt(pTraceSession->m_tmfFile[kk].Right(40), pLogSession);
//
// get the protection
//
WaitForSingleObject(g_hGetTraceEvent, INFINITE);
//
// Get the format GUIDs from the TMF file(s)
//
if(0 == GetTraceGuids((LPTSTR)(LPCTSTR)pTraceSession->m_tmfFile[kk],
(PLIST_ENTRY *)&m_pEventListHead)) {
str.Format(_T("Failed To Get Format Information For Logger %ls"), pLogSession->m_evmFile.LoggerName);
AfxMessageBox(str);
}
//
// Release the protection
//
SetEvent(g_hGetTraceEvent);
}
} else {
CString defaultPath;
if((GetModuleFileName(NULL, defaultPath.GetBuffer(500), 500)) == 0) {
defaultPath.Empty();
} else {
defaultPath = (LPCTSTR)defaultPath.Left(defaultPath.ReverseFind('\\') + 1);
}
defaultPath +=_T("default.tmf");
//
// If path is empty, the TMF path environment variable will
// be used as-is by default.
//
if(!pTraceSession->m_tmfPath.IsEmpty()){
//
// If the path is set we set the TMF path
// environment variable
//
SetTraceFormatParameter(ParameterTraceFormatSearchPath, (PVOID)(LPCTSTR)pTraceSession->m_tmfPath);
}
//
// Still have to call GetTraceGuids
//
WaitForSingleObject(g_hGetTraceEvent, INFINITE);
//
// Get the format info
//
GetTraceGuids((LPTSTR)(LPCTSTR)defaultPath,
(PLIST_ENTRY *)&m_pEventListHead);
//
// Release the protection
//
SetEvent(g_hGetTraceEvent);
}
}
//
// Open and get a handle to the trace session
//
pLogSession->m_traceHandle = OpenTrace(&pLogSession->m_evmFile);
if(INVALID_HANDLE_VALUE == (HANDLE)pLogSession->m_traceHandle) {
str.Format(_T("OpenTrace failed for logger %ls\nError returned: %d"),
pLogSession->GetDisplayName(),
GetLastError());
AfxMessageBox(str);
continue;
}
//
// Save the handle in our array for OpenTrace
//
m_traceHandleArray[m_traceHandleCount++] = pLogSession->m_traceHandle;
//
// Add this displayDlg to the global hash table keyed
// by log session name
//
g_loggerNameToDisplayDlgHash.SetAt(pLogSession->GetDisplayName(), this);
}
//
// Release the array protection
//
ReleaseMutex(m_hSessionArrayMutex);
//
// If we have at least one valid handle start
// our real-time thread processing events
//
if(m_traceHandleCount != 0) {
//
// Set the real-time processing start event and thus kick
// the real-time thread into processing events
//
SetEvent(m_hRealTimeProcessingStartEvent);
}
return TRUE;
}
//
// This function handles writing the summary file. Heavily borrowed code
// from TraceFmt here.
//
VOID CDisplayDlg::WriteSummaryFile()
{
CLogSession *pLogSession;
CString str;
CStdioFile summaryFile;
TCHAR *pSummaryBlock;
__int64 elapsedTime;
LONG ii;
//
// Attempt to open the summary file
//
if(!summaryFile.Open(m_summaryFileName, CFile::modeCreate |
CFile::modeReadWrite)) {
AfxMessageBox(_T("Unable To Create Summary File"));
return;
}
//
// allocate some memory
//
pSummaryBlock = new TCHAR[SIZESUMMARYBLOCK];
if(NULL == pSummaryBlock) {
AfxMessageBox(_T("Unable To Create Summary File"));
return;
}
//
// Write the header
//
str.Format(_T("Files Processed:\n"));
summaryFile.WriteString(str);
//
// Get the array protection
//
WaitForSingleObject(m_hSessionArrayMutex, INFINITE);
for(ii = 0; ii < m_sessionArray.GetSize(); ii++) {
pLogSession = (CLogSession *)m_sessionArray[ii];
if(NULL == pLogSession) {
continue;
}
str.Format(_T("\t%s\n"),pLogSession->m_logFileName);
summaryFile.WriteString(str);
}
//
// Release the array protection
//
ReleaseMutex(m_hSessionArrayMutex);
//
// Get the duration of the session
//
GetTraceElapseTime(&elapsedTime);
//
// Write out the counts
//
str.Format(
_T("Total Buffers Processed %d\n")
_T("Total Events Processed %d\n")
_T("Total Events Lost %d\n")
_T("Elapsed Time %I64d sec\n"),
m_totalBuffersRead,
m_totalEventCount,
m_totalEventsLost,
(elapsedTime / 10000000) );
summaryFile.WriteString(str);
str.Format(
_T("+--------------------------------------------------------------------------------------+\n")
_T("|%10s %-20s %-10s %-36s|\n")
_T("+--------------------------------------------------------------------------------------+\n"),
_T("EventCount"),
_T("EventName"),
_T("EventType"),
_T("Guid"));
summaryFile.WriteString(str);
//
// Write out the summary block
//
SummaryTraceEventList(pSummaryBlock, SIZESUMMARYBLOCK, m_pEventListHead);
str.Format(_T("%s+--------------------------------------------------------------------------------------+\n"),
pSummaryBlock);
summaryFile.WriteString(str);
//
// Close the file
//
summaryFile.Close();
//
// Free our memory
//
delete [] pSummaryBlock;
}
ULONG WINAPI BufferCallback(PEVENT_TRACE_LOGFILE pLog)
{
CDisplayDlg *pDisplayDlg;
CString str;
//
// Get the logger name from the passed in struct
//
str.Format(_T("%s"), pLog->LoggerName);
//
// Get our logsession from the global hash table using the logger name
//
g_loggerNameToDisplayDlgHash.Lookup(str, (void*&)pDisplayDlg);
//
// If we got our displayDlg, update the counts
//
if(NULL != pDisplayDlg) {
pDisplayDlg->m_totalBuffersRead++;
pDisplayDlg->m_totalEventsLost += pLog->EventsLost;
::PostMessage(pDisplayDlg->m_hMainWnd, WM_USER_UPDATE_LOGSESSION_LIST, 0, 0);
}
return TRUE;
}
//
// Sort handler
VOID CDisplayDlg::OnDoSort(NMHDR * pNmhdr, LRESULT * pResult)
{
NMLISTVIEW *pLV = (NMLISTVIEW *)pNmhdr;
//
// Sort the table by the selected column's data
//
SortTable(pLV->iItem);
//
// Force a redraw of the data
//
m_displayCtrl.RedrawItems(m_displayCtrl.GetTopIndex(),
m_displayCtrl.GetTopIndex() + m_displayCtrl.GetCountPerPage());
m_displayCtrl.UpdateWindow();
}
//
// EventHandler() is only a wrapper, it calls FormatTraceEvent() in TracePrt.
//
VOID CDisplayDlg::EventHandler(PEVENT_TRACE pEvent)
{
CString str;
CString tempString;
GUID guidValue;
CString guidString;
PSTRUCTUREDMESSAGE pStructuredMessage;
CTraceMessage *pTraceMessage;
DWORD itemCount;
DWORD time;
CTraceViewApp *pMainWnd;
//
// Make sure we got an event
//
if (NULL == pEvent) {
return;
}
//
// Get traceprt protection
//
WaitForSingleObject(g_hGetTraceEvent, INFINITE);
//
// FormatTraceEvent fills in our event buffer and updates some
// info in the event list for the summary file
//
if(FormatTraceEvent(m_pEventListHead,
pEvent,
m_pEventBuf,
EVENT_BUFFER_SIZE,
NULL) <= 0) {
//
// Release traceprt protection
//
SetEvent(g_hGetTraceEvent);
return;
}
//
// Release traceprt protection
//
SetEvent(g_hGetTraceEvent);
//
// Get the structured message struct from the event buffer
//
pStructuredMessage = (PSTRUCTUREDMESSAGE)&m_pEventBuf[0];
//
// Get a pointer to the main wnd
//
pMainWnd = (CTraceViewApp *)AfxGetApp();
if(NULL == pMainWnd) {
return;
}
//
// Allocate a message struct from the main frame
//
pTraceMessage = pMainWnd->AllocateTraceEventBlock();
if(NULL == pTraceMessage) {
return;
}
//
// Get the message from the event buffer
//
memcpy(&pTraceMessage->m_TraceGuid,
&pStructuredMessage->TraceGuid,
sizeof(GUID));
//
// Copy the message struct to our own struct
//
pTraceMessage->m_GuidName =
(pStructuredMessage->GuidName ? &m_pEventBuf[pStructuredMessage->GuidName/sizeof(TCHAR)] :_T(""));
pTraceMessage->m_GuidTypeName.Format(_T("%s"),
(pStructuredMessage->GuidTypeName ? &m_pEventBuf[pStructuredMessage->GuidTypeName/sizeof(TCHAR)] :_T("")));
pTraceMessage->m_ThreadId = pStructuredMessage->ThreadId;
memcpy(&pTraceMessage->m_SystemTime,
&pStructuredMessage->SystemTime,
sizeof(SYSTEMTIME));
memcpy(&pTraceMessage->m_UserTime,
&pStructuredMessage->UserTime,
sizeof(ULONG));
memcpy(&pTraceMessage->m_KernelTime,
&pStructuredMessage->KernelTime,
sizeof(ULONG));
pTraceMessage->m_SequenceNum = pStructuredMessage->SequenceNum;
pTraceMessage->m_ProcessId = pStructuredMessage->ProcessId;
pTraceMessage->m_CpuNumber = pStructuredMessage->CpuNumber;
pTraceMessage->m_Indent = pStructuredMessage->Indent;
pTraceMessage->m_FlagsName.Format(_T("%s"),
(pStructuredMessage->FlagsName ? &m_pEventBuf[pStructuredMessage->FlagsName/sizeof(TCHAR)] :_T("")));
pTraceMessage->m_LevelName.Format(_T("%s"),
(pStructuredMessage->LevelName ? &m_pEventBuf[pStructuredMessage->LevelName/sizeof(TCHAR)] :_T("")));
pTraceMessage->m_FunctionName.Format(_T("%s"),
(pStructuredMessage->FunctionName ? &m_pEventBuf[pStructuredMessage->FunctionName/sizeof(TCHAR)] :_T("")));
pTraceMessage->m_ComponentName.Format(_T("%s"),
(pStructuredMessage->ComponentName ? &m_pEventBuf[pStructuredMessage->ComponentName/sizeof(TCHAR)] :_T("")));
pTraceMessage->m_SubComponentName.Format(_T("%s"),
(pStructuredMessage->SubComponentName ? &m_pEventBuf[pStructuredMessage->SubComponentName/sizeof(TCHAR)] :_T("")));
pTraceMessage->m_Message.Format(_T("%s"),
(pStructuredMessage->FormattedString ? &m_pEventBuf[pStructuredMessage->FormattedString/sizeof(TCHAR)] :_T("")));
//
// Get our trace event array protection
//
WaitForSingleObject(m_hTraceEventMutex,INFINITE);
//
// If we're in a low memory situation, drop one entry for every one we add
//
if( m_traceArray.GetSize() > MaxTraceEntries) {
delete m_traceArray.GetAt(0);
//
// Slide 'em all down...
//
m_traceArray.RemoveAt(0);
}
//
// Add the event to the array
//
m_traceArray.Add(pTraceMessage);
//
// Update the item count for the list control so that
// the display gets updated
//
itemCount = (LONG)m_traceArray.GetSize();
//
// Release our trace event array protection
//
ReleaseMutex(m_hTraceEventMutex);
//
// dump the event to the output file if any
//
if(m_bWriteListingFile &&
m_bListingFileOpen) {
//
// Glorious hack to get FILETIME back into string format
// Not sure this works for different time zones or daylight savings
//
CTime kernelTime(pStructuredMessage->KernelTime);
CTime userTime(pStructuredMessage->UserTime);
CString system;
CString kernel;
CString user;
system.Format(_T("%02d\\%02d\\%4d-%02d:%02d:%02d"),
pStructuredMessage->SystemTime.wMonth,
pStructuredMessage->SystemTime.wDay,
pStructuredMessage->SystemTime.wYear,
pStructuredMessage->SystemTime.wHour,
pStructuredMessage->SystemTime.wMinute,
pStructuredMessage->SystemTime.wSecond,
pStructuredMessage->SystemTime.wMilliseconds);
if(kernelTime.GetYear() == 1969) {
kernel.Format(_T(" "));
} else {
kernel.Format(_T("%s-%02d:%02d:%02d"),
kernelTime.Format("%m\\%d\\%Y"),
kernelTime.GetHour() + 5,
kernelTime.GetMinute(),
kernelTime.GetSecond());
}
if(userTime.GetYear() == 1969) {
user.Format(_T(" "));
} else {
user.Format(_T("%s-%02d:%02d:%02d"),
userTime.Format("%m\\%d\\%Y"),
userTime.GetHour() + 5,
userTime.GetMinute(),
userTime.GetSecond());
}
//
// Need to reformat with good timestamps for the output file.
// Output Order --> Name FileName_Line# FunctionName ProcessID ThreadID
// CPU# Seq# SystemTime KernelTime UserTime Indent
// FlagsName LevelName ComponentName SubComponentName
// Message at end
//
str.Format(_T("%s %s %s %X %X %d %u %s %s %s %s %s %s %s %s %s"),
(pStructuredMessage->GuidName ? &m_pEventBuf[pStructuredMessage->GuidName/sizeof(TCHAR)] :_T("")),
(pStructuredMessage->GuidTypeName ? &m_pEventBuf[pStructuredMessage->GuidTypeName/sizeof(TCHAR)] :_T("")),
(pStructuredMessage->FunctionName ? &m_pEventBuf[pStructuredMessage->FunctionName/sizeof(TCHAR)] :_T("")),
pStructuredMessage->ProcessId,
pStructuredMessage->ThreadId,
pStructuredMessage->CpuNumber,
pStructuredMessage->SequenceNum,
system,
kernel,
user,
(pStructuredMessage->Indent ? &m_pEventBuf[pStructuredMessage->Indent/sizeof(TCHAR)] :_T("")),
(pStructuredMessage->FlagsName ? &m_pEventBuf[pStructuredMessage->FlagsName/sizeof(TCHAR)] :_T("")),
(pStructuredMessage->LevelName ? &m_pEventBuf[pStructuredMessage->LevelName/sizeof(TCHAR)] :_T("")),
(pStructuredMessage->ComponentName ? &m_pEventBuf[pStructuredMessage->ComponentName/sizeof(TCHAR)] :_T("")),
(pStructuredMessage->SubComponentName ? &m_pEventBuf[pStructuredMessage->SubComponentName/sizeof(TCHAR)] :_T("")),
(pStructuredMessage->FormattedString ? &m_pEventBuf[pStructuredMessage->FormattedString/sizeof(TCHAR)] :_T("")));
str +=_T("\n");
m_listingFile.WriteString(str);
}
//
// Update the event count for the summary file
//
m_totalEventCount++;
//
// Empty the string buffer (not strictly necessary)
//
str.Empty();
}
VOID CDisplayDlg::OnTimer(UINT nIDEvent)
{
int itemCount;
static int previousCount = 0;
static BOOL bAutoSizeOnce = TRUE;
static CTraceMessage * msgLastSeen=0;
//
// This is a really bad hack.
// Couldn't figure out anyway to get notified when
// the DisplayDlg window has actually been displayed.
// Until it is displayed, then AutoSizeColumns won't
// work correctly for the last column. Calling it here
// seems to fix the problem. There has to be a better way.
//
if(bAutoSizeOnce) {
AutoSizeColumns();
bAutoSizeOnce = FALSE;
}
//
// Get our trace event array protection
//
WaitForSingleObject(m_hTraceEventMutex,INFINITE);
//
// Update the item count for the list control so that
// the display gets updated
//
itemCount = (LONG)m_traceArray.GetSize();
//
// Release our trace event array protection
//
ReleaseMutex(m_hTraceEventMutex);
if(itemCount == 0) {
msgLastSeen = NULL;
return;
}
if( itemCount <= MaxTraceEntries) {
if( itemCount == previousCount ) {
return;
}
} else {
if(m_traceArray.GetAt(0) == msgLastSeen) {
return;
}
msgLastSeen = m_traceArray.GetAt(0);
}
previousCount = itemCount;
//
// Sort the table of event messages
//
SortTable();
//
// Adjust the trace display item count
//
m_displayCtrl.SetItemCountEx(itemCount,
LVSICF_NOINVALIDATEALL|LVSICF_NOSCROLL);
m_displayCtrl.RedrawItems(m_displayCtrl.GetTopIndex(),
m_displayCtrl.GetTopIndex() + m_displayCtrl.GetCountPerPage());
m_displayCtrl.UpdateWindow();
//
// Ensure that the last item is visible if requested.
//
if(m_bShowLatest) {
m_displayCtrl.EnsureVisible(itemCount - 1,
FALSE);
}
//
// Force an update of the event count in the display
//
::PostMessage(m_hMainWnd, WM_USER_UPDATE_LOGSESSION_LIST, 0, 0);
}
VOID CDisplayDlg::SetState(LOG_SESSION_STATE StateValue)
{
CLogSession *pLogSession = NULL;
//
// Get the array protection
//
WaitForSingleObject(m_hSessionArrayMutex, INFINITE);
for(LONG ii = 0; ii < m_sessionArray.GetSize(); ii++) {
pLogSession = (CLogSession *)m_sessionArray[ii];
if(NULL == pLogSession) {
continue;
}
//
// Set the log session's state
//
pLogSession->SetState(StateValue);
}
//
// Release the array protection
//
ReleaseMutex(m_hSessionArrayMutex);
::PostMessage(m_hMainWnd, WM_USER_UPDATE_LOGSESSION_LIST, 0, 0);
}
//
// Macro to create our event callback functions. This is only
// necessary as there is no context we can pass into our event
// callback function. So, we setup a unique event callback for
// each log session. We have 64 here, but the number will have
// to increase to match the total number of possible loggers
//
#define MAKE_EVENT_CALLBACK(n) \
VOID WINAPI DumpEvent##n(PEVENT_TRACE pEvent) \
{ \
CDisplayDlg *pDisplayDlg; \
g_displayIDToDisplayDlgHash.Lookup(n, (void *&)pDisplayDlg);\
if(NULL != pDisplayDlg) { \
pDisplayDlg->EventHandler(pEvent); \
} \
}
//
// Make 64 of them initially
//
MAKE_EVENT_CALLBACK(0);
MAKE_EVENT_CALLBACK(1);
MAKE_EVENT_CALLBACK(2);
MAKE_EVENT_CALLBACK(3);
MAKE_EVENT_CALLBACK(4);
MAKE_EVENT_CALLBACK(5);
MAKE_EVENT_CALLBACK(6);
MAKE_EVENT_CALLBACK(7);
MAKE_EVENT_CALLBACK(8);
MAKE_EVENT_CALLBACK(9);
MAKE_EVENT_CALLBACK(10);
MAKE_EVENT_CALLBACK(11);
MAKE_EVENT_CALLBACK(12);
MAKE_EVENT_CALLBACK(13);
MAKE_EVENT_CALLBACK(14);
MAKE_EVENT_CALLBACK(15);
MAKE_EVENT_CALLBACK(16);
MAKE_EVENT_CALLBACK(17);
MAKE_EVENT_CALLBACK(18);
MAKE_EVENT_CALLBACK(19);
MAKE_EVENT_CALLBACK(20);
MAKE_EVENT_CALLBACK(21);
MAKE_EVENT_CALLBACK(22);
MAKE_EVENT_CALLBACK(23);
MAKE_EVENT_CALLBACK(24);
MAKE_EVENT_CALLBACK(25);
MAKE_EVENT_CALLBACK(26);
MAKE_EVENT_CALLBACK(27);
MAKE_EVENT_CALLBACK(28);
MAKE_EVENT_CALLBACK(29);
MAKE_EVENT_CALLBACK(30);
MAKE_EVENT_CALLBACK(31);
MAKE_EVENT_CALLBACK(32);
MAKE_EVENT_CALLBACK(33);
MAKE_EVENT_CALLBACK(34);
MAKE_EVENT_CALLBACK(35);
MAKE_EVENT_CALLBACK(36);
MAKE_EVENT_CALLBACK(37);
MAKE_EVENT_CALLBACK(38);
MAKE_EVENT_CALLBACK(39);
MAKE_EVENT_CALLBACK(40);
MAKE_EVENT_CALLBACK(41);
MAKE_EVENT_CALLBACK(42);
MAKE_EVENT_CALLBACK(43);
MAKE_EVENT_CALLBACK(44);
MAKE_EVENT_CALLBACK(45);
MAKE_EVENT_CALLBACK(46);
MAKE_EVENT_CALLBACK(47);
MAKE_EVENT_CALLBACK(48);
MAKE_EVENT_CALLBACK(49);
MAKE_EVENT_CALLBACK(50);
MAKE_EVENT_CALLBACK(51);
MAKE_EVENT_CALLBACK(52);
MAKE_EVENT_CALLBACK(53);
MAKE_EVENT_CALLBACK(54);
MAKE_EVENT_CALLBACK(55);
MAKE_EVENT_CALLBACK(56);
MAKE_EVENT_CALLBACK(57);
MAKE_EVENT_CALLBACK(58);
MAKE_EVENT_CALLBACK(59);
MAKE_EVENT_CALLBACK(60);
MAKE_EVENT_CALLBACK(61);
MAKE_EVENT_CALLBACK(62);
MAKE_EVENT_CALLBACK(63);