BOOL CDynamoRIOView::Refresh() { if (m_selected_pid <= 0) { ZeroStrings(); return TRUE; } // We have to grab new stats every refresh dr_statistics_t *new_stats = get_dynamorio_stats(m_selected_pid); if (new_stats == NULL) { if (m_stats != NULL) { // Leave the stats for an exited process in place, for viewing // and copying } else return TRUE; } else { if (m_stats != NULL) free_dynamorio_stats(m_stats); m_stats = new_stats; } uint i; #define MAX_VISIBLE_STATS 75 #define STATS_BUFSZ (MAX_VISIBLE_STATS*(sizeof(single_stat_t)*2/*cover %10u, etc.*/)) TCHAR buf[STATS_BUFSZ]; TCHAR *c = buf; buf[0] = _T('\0'); // If I just use a CString hooked up via DDX, re-setting the // text causes the top of the visible box to show the top of // the stats string; plus the scrollbar goes to the top, // unless held in place; probably any reset of the string // does an auto-reset of the display and scrollbar position. // To have all the text in there do this: // int scroll_pos = m_StatsCtl.GetScrollPos(SB_VERT); // m_StatsCtl.SetWindowText(buf); // m_StatsCtl.LineScroll(scroll_pos); // But then there's a lot of flickering: too much. // We only put visible text lines in the CEdit box, to reduce the // flicker. It's too hard to do it w/ the CEdit's own scrollbar, // which sets itself based on the actual text, so we have a // separate one. // HACK: I don't know how to find out how many lines will // fit w/o putting actual text in there if (m_StatsViewLines == 0) { for (i = 0; i < m_stats->num_stats && i < MAX_VISIBLE_STATS /* can't be more than this */; i++) { if (c >= &buf[STATS_BUFSZ-STAT_NAME_MAX_LEN*2]) break; c += PrintStat(c, i, FALSE/*no filter*/); assert(c < &buf[STATS_BUFSZ-1]); } m_StatsCtl.SetWindowText(buf); UpdateData(FALSE); // write to screen // I tried having only one screenful of string there, and // setting the scrollbar range to be larger, but it doesn't // seem to support that. RECT rect; m_StatsCtl.GetRect(&rect); CPoint pos(rect.right, rect.bottom); m_StatsViewLines = HIWORD(m_StatsCtl.CharFromPos(pos)); assert(m_StatsViewLines > 0); m_StatsSB.SetScrollRange(0, m_stats->num_stats-1, TRUE/*redraw*/); c = buf; SCROLLINFO info; info.cbSize = sizeof(SCROLLINFO); info.fMask = SIF_PAGE; info.nPage = m_StatsViewLines; m_StatsSB.SetScrollInfo(&info); } int scroll_pos = m_StatsSB.GetScrollPos(); DWORD shown = 0; uint printed; for (i = scroll_pos; i < m_stats->num_stats && shown < m_StatsViewLines; i++) { if (c >= &buf[STATS_BUFSZ-STAT_NAME_MAX_LEN*2]) break; printed = PrintStat(c, i, TRUE/*filter*/); c += printed; assert(c < &buf[STATS_BUFSZ-1]); if (printed > 0) shown++; } m_StatsCtl.SetWindowText(buf); // num_stats could have changed so update m_StatsSB.SetScrollRange(0, m_stats->num_stats-1, TRUE/*redraw*/); if (new_stats == NULL) m_Exited = _T(" Exited"); // line right end up with Running else m_Exited = _T("Running"); #ifndef DRSTATS_DEMO m_LogLevel.Format(_T("%d"), m_stats->loglevel); m_LogMask.Format(_T("0x%05X"), m_stats->logmask); m_LogDir.Format(_T("%") ASCII_PRINTF, m_stats->logdir); #endif if (m_clientStats != NULL) { #define CLIENTSTATS_BUFSZ USHRT_MAX TCHAR buf[CLIENTSTATS_BUFSZ]; PrintClientStats(buf, &buf[CLIENTSTATS_BUFSZ-1]); m_ClientStats.Format(_T("%s"), buf); } else m_ClientStats.Format(_T("")); UpdateData(FALSE); // write to screen return TRUE; }
void CDynamoRIOView::OnEditCopystats() { if (m_ProcessList.GetCurSel() == 0) { MessageBox(_T("No instance selected"), _T("Error"), MB_OK | MYMBFLAGS); return; } if (!OpenClipboard()) { MessageBox(_T("Error opening clipboard"), _T("Error"), MB_OK | MYMBFLAGS); return; } EmptyClipboard(); #define CLIPBOARD_BUFSZ USHRT_MAX TCHAR buf[CLIPBOARD_BUFSZ]; TCHAR *pos = buf; if (m_selected_pid > 0) { if (m_stats != NULL) { pos += _stprintf(pos, _T("Process id = %d\r\n"), m_stats->process_id); pos += _stprintf(pos, _T("Process name = %") ASCII_PRINTF _T("\r\n"), m_stats->process_name); pos += _stprintf(pos, _T("Status = %s\r\n"), m_Exited.GetBuffer(0)); #ifndef DRSTATS_DEMO pos += _stprintf(pos, _T("Log mask = %s\r\n"), m_LogMask.GetBuffer(0)); pos += _stprintf(pos, _T("Log level = %s\r\n"), m_LogLevel.GetBuffer(0)); pos += _stprintf(pos, _T("Log file = %s\r\n"), m_LogDir.GetBuffer(0)); #endif pos += _stprintf(pos, _T("\r\nSTATS\r\n")); uint i; for (i = 0; i < m_stats->num_stats; i++) { if (pos >= &buf[STATS_BUFSZ-STAT_NAME_MAX_LEN*2]) break; // FIXME: Filter here too pos += PrintStat(pos, i, TRUE/*filter*/); assert(pos < &buf[STATS_BUFSZ-1]); } } else { CString pname; m_ProcessList.GetLBText(m_ProcessList.GetCurSel(), pname); _stprintf(pos, _T("%s"), pname); pos += _tcslen(pos); } } if (m_clientStats != NULL) { pos += PrintClientStats(pos, &buf[STATS_BUFSZ-1]); } size_t len = _tcslen(buf); // Allocate a global memory object for the text. HGLOBAL hglbCopy = GlobalAlloc(GMEM_DDESHARE, (len + 1) * sizeof(TCHAR)); if (hglbCopy == NULL) { CloseClipboard(); return; } // Lock the handle and copy the text to the buffer. LPTSTR lptstrCopy = (LPTSTR) GlobalLock(hglbCopy); memcpy(lptstrCopy, buf, (len + 1) * sizeof(TCHAR)); lptstrCopy[len] = (TCHAR) 0; // null TCHARacter GlobalUnlock(hglbCopy); // Place the handle on the clipboard. SetClipboardData( #ifdef UNICODE CF_UNICODETEXT, #else CF_TEXT, #endif hglbCopy); CloseClipboard(); }
void G_PrintStats(void) { const playerStat_t *columns; gclient_t *cl; int stats[STAT_MAX]; int bestStats[STAT_MAX]; qboolean reallyBest[STAT_MAX] = { qfalse }; int i, j; if (level.numPlayingClients == 0) { return; } cl = &level.clients[level.sortedClients[0]]; GetStats(bestStats, cl); for (i = 1; i < level.numPlayingClients; i++) { cl = &level.clients[level.sortedClients[i]]; GetStats(stats, cl); for (j = 0; j <= STAT_MAX_ASC; j++) { if (stats[j] != bestStats[j]) { reallyBest[j] = qtrue; } if (stats[j] > bestStats[j]) { bestStats[j] = stats[j]; } } for (; j < STAT_MAX; j++) { if (stats[j] != bestStats[j]) { reallyBest[j] = qtrue; } if (stats[j] < bestStats[j]) { bestStats[j] = stats[j]; } } } // Don't highlight the stat if it's the same for all players for (j = 0; j < STAT_MAX; j++) { if (!reallyBest[j]) { bestStats[j] = INT_MAX; } } // disable stats irrelevant in current gametype. column arrays can // be removed at this point, but i'd rather keep line length under // firm control statCol[STAT_ACC].disabled = HasSetSaberOnly(); statCol[STAT_IMPRESSIVE].disabled = (g_spawnWeapons.integer & WP_DISRUPTOR); trap_SendServerCommand(-1, "print \"\n\""); if (GT_Team(g_gametype.integer) && g_gametype.integer != GT_REDROVER) { if (g_gametype.integer == GT_CTF) { if (g_instagib.integer) columns = ictfColumns; else columns = ctfColumns; } else { if (g_instagib.integer) columns = iffaColumns; else columns = tffaColumns; } PrintStatsHeader(columns); PrintStatsSeparator(columns, teamColorString[TEAM_RED]); for (i = 0; i < level.numPlayingClients; i++) { cl = level.clients + level.sortedClients[i]; if (cl->sess.sessionTeam == TEAM_RED) PrintClientStats(cl, columns, bestStats); } PrintStatsSeparator(columns, teamColorString[TEAM_BLUE]); for (i = 0; i < level.numPlayingClients; i++) { cl = level.clients + level.sortedClients[i]; if (cl->sess.sessionTeam == TEAM_BLUE) { PrintClientStats(cl, columns, bestStats); } } } else { if (g_instagib.integer) { columns = iffaColumns; } else if (g_gametype.integer == GT_REDROVER) { columns = tffaColumns; } else { columns = ffaColumns; } PrintStatsHeader(columns); PrintStatsSeparator(columns, teamColorString[TEAM_FREE]); for (i = 0; i < level.numPlayingClients; i++) { cl = level.clients + level.sortedClients[i]; PrintClientStats(cl, columns, bestStats); } } trap_SendServerCommand(-1, "print \"\n\""); }