////////////////////////////////////////////////////////////////////////////// // Copyright (c) 2002 Microsoft Corporation. All rights reserved. // Copyright (c) 2002 OSR Open Systems Resources, Inc. // // DisplayDlg.cpp : implementation file ////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include #include #include #include extern "C" { #include } #include #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(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);