| OLD | NEW |
| (Empty) |
| 1 using System; | |
| 2 using System.Collections.Generic; | |
| 3 using System.ComponentModel; | |
| 4 using System.Data; | |
| 5 using System.Diagnostics; | |
| 6 using System.Drawing; | |
| 7 using System.IO; | |
| 8 using System.Linq; | |
| 9 using System.Management; | |
| 10 using System.Text; | |
| 11 using System.Threading.Tasks; | |
| 12 using System.Windows.Forms; | |
| 13 | |
| 14 using ChromeDebug.LowLevel; | |
| 15 | |
| 16 namespace ChromeDebug { | |
| 17 // The form that is displayed to allow the user to select processes to attach
to. Note that we | |
| 18 // cannot interact with the DTE object from here (I assume this is because the
dialog is running | |
| 19 // on a different thread, although I don't fully understand), so any access to
the DTE object | |
| 20 // will have to be done through events that get posted back to the main packag
e thread. | |
| 21 public partial class AttachDialog : Form { | |
| 22 private class ProcessViewItem : ListViewItem { | |
| 23 public ProcessViewItem() { | |
| 24 Category = ProcessCategory.Other; | |
| 25 MachineType = LowLevelTypes.MachineType.UNKNOWN; | |
| 26 } | |
| 27 | |
| 28 public string Exe; | |
| 29 public int ProcessId; | |
| 30 public int SessionId; | |
| 31 public string Title; | |
| 32 public string DisplayCmdLine; | |
| 33 public string[] CmdLineArgs; | |
| 34 public ProcessCategory Category; | |
| 35 public LowLevelTypes.MachineType MachineType; | |
| 36 | |
| 37 public ProcessDetail Detail; | |
| 38 } | |
| 39 | |
| 40 private Dictionary<ProcessCategory, List<ProcessViewItem>> loadedProcessTabl
e = null; | |
| 41 private Dictionary<ProcessCategory, ListViewGroup> processGroups = null; | |
| 42 private List<int> selectedProcesses = null; | |
| 43 | |
| 44 public AttachDialog() { | |
| 45 InitializeComponent(); | |
| 46 | |
| 47 loadedProcessTable = new Dictionary<ProcessCategory, List<ProcessViewItem>
>(); | |
| 48 processGroups = new Dictionary<ProcessCategory, ListViewGroup>(); | |
| 49 selectedProcesses = new List<int>(); | |
| 50 | |
| 51 // Create and initialize the groups and process lists only once. On a rese
t | |
| 52 // we don't clear the groups manually, clearing the list view should clear
the | |
| 53 // groups. And we don't clear the entire processes_ dictionary, only the | |
| 54 // individual buckets inside the dictionary. | |
| 55 foreach (object value in Enum.GetValues(typeof(ProcessCategory))) { | |
| 56 ProcessCategory category = (ProcessCategory)value; | |
| 57 | |
| 58 ListViewGroup group = new ListViewGroup(category.ToGroupTitle()); | |
| 59 processGroups[category] = group; | |
| 60 listViewProcesses.Groups.Add(group); | |
| 61 | |
| 62 loadedProcessTable[category] = new List<ProcessViewItem>(); | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 // Provides an iterator that evaluates to the process ids of the entries tha
t are selected | |
| 67 // in the list view. | |
| 68 public IEnumerable<int> SelectedItems { | |
| 69 get { | |
| 70 foreach (ProcessViewItem item in listViewProcesses.SelectedItems) | |
| 71 yield return item.ProcessId; | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 private void AttachDialog_Load(object sender, EventArgs e) { | |
| 76 RepopulateListView(); | |
| 77 } | |
| 78 | |
| 79 // Remove command line arguments that we aren't interested in displaying as
part of the command | |
| 80 // line of the process. | |
| 81 private string[] FilterCommandLine(string[] args) { | |
| 82 Func<string, int, bool> AllowArgument = delegate(string arg, int index) { | |
| 83 if (index == 0) | |
| 84 return false; | |
| 85 return !arg.StartsWith("--force-fieldtrials", StringComparison.CurrentCu
ltureIgnoreCase); | |
| 86 }; | |
| 87 | |
| 88 // The force-fieldtrials command line option makes the command line view u
seless, so remove | |
| 89 // it. Also remove args[0] since that is the process name. | |
| 90 args = args.Where(AllowArgument).ToArray(); | |
| 91 return args; | |
| 92 } | |
| 93 | |
| 94 private void ReloadNativeProcessInfo() { | |
| 95 foreach (List<ProcessViewItem> list in loadedProcessTable.Values) { | |
| 96 list.Clear(); | |
| 97 } | |
| 98 | |
| 99 Process[] processes = Process.GetProcesses(); | |
| 100 foreach (Process p in processes) { | |
| 101 ProcessViewItem item = new ProcessViewItem(); | |
| 102 try { | |
| 103 item.Detail = new ProcessDetail(p.Id); | |
| 104 if (item.Detail.CanReadPeb && item.Detail.CommandLine != null) { | |
| 105 item.CmdLineArgs = Utility.SplitArgs(item.Detail.CommandLine); | |
| 106 item.DisplayCmdLine = GetFilteredCommandLineString(item.CmdLineArgs)
; | |
| 107 } | |
| 108 item.MachineType = item.Detail.MachineType; | |
| 109 } | |
| 110 catch (Exception) { | |
| 111 // Generally speaking, an exception here means the process is privileg
ed and we cannot | |
| 112 // get any information about the process. For those processes, we wil
l just display the | |
| 113 // information that the Framework gave us in the Process structure. | |
| 114 } | |
| 115 | |
| 116 // If we don't have the machine type, its privilege level is high enough
that we won't be | |
| 117 // able to attach a debugger to it anyway, so skip it. | |
| 118 if (item.MachineType == LowLevelTypes.MachineType.UNKNOWN) | |
| 119 continue; | |
| 120 | |
| 121 item.ProcessId = p.Id; | |
| 122 item.SessionId = p.SessionId; | |
| 123 item.Title = p.MainWindowTitle; | |
| 124 item.Exe = p.ProcessName; | |
| 125 if (item.CmdLineArgs != null) | |
| 126 item.Category = DetermineProcessCategory(item.CmdLineArgs); | |
| 127 | |
| 128 List<ProcessViewItem> items = loadedProcessTable[item.Category]; | |
| 129 item.Group = processGroups[item.Category]; | |
| 130 items.Add(item); | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 // Filter the command line arguments to remove extraneous arguments that we
don't wish to | |
| 135 // display. | |
| 136 private string GetFilteredCommandLineString(string[] args) { | |
| 137 if (args == null || args.Length == 0) | |
| 138 return string.Empty; | |
| 139 | |
| 140 args = FilterCommandLine(args); | |
| 141 return string.Join(" ", args, 0, args.Length); | |
| 142 } | |
| 143 | |
| 144 // Using a heuristic based on the command line, tries to determine what type
of process this | |
| 145 // is. | |
| 146 private ProcessCategory DetermineProcessCategory(string[] cmdline) { | |
| 147 if (cmdline == null || cmdline.Length == 0) | |
| 148 return ProcessCategory.Other; | |
| 149 | |
| 150 string file = Path.GetFileName(cmdline[0]); | |
| 151 if (file.Equals("delegate_execute.exe", StringComparison.CurrentCultureIgn
oreCase)) | |
| 152 return ProcessCategory.DelegateExecute; | |
| 153 else if (file.Equals("chrome.exe", StringComparison.CurrentCultureIgnoreCa
se)) { | |
| 154 if (cmdline.Contains("--type=renderer")) | |
| 155 return ProcessCategory.Renderer; | |
| 156 else if (cmdline.Contains("--type=plugin") || cmdline.Contains("--type
=ppapi")) | |
| 157 return ProcessCategory.Plugin; | |
| 158 else if (cmdline.Contains("--type=gpu-process")) | |
| 159 return ProcessCategory.Gpu; | |
| 160 else if (cmdline.Contains("--type=service")) | |
| 161 return ProcessCategory.Service; | |
| 162 else if (cmdline.Any(arg => arg.StartsWith("-ServerName"))) | |
| 163 return ProcessCategory.MetroViewer; | |
| 164 else | |
| 165 return ProcessCategory.Browser; | |
| 166 } else | |
| 167 return ProcessCategory.Other; | |
| 168 } | |
| 169 | |
| 170 private void InsertCategoryItems(ProcessCategory category) { | |
| 171 foreach (ProcessViewItem item in loadedProcessTable[category]) { | |
| 172 item.SubItems.Add(item.Exe); | |
| 173 item.SubItems.Add(item.ProcessId.ToString()); | |
| 174 item.SubItems.Add(item.Title); | |
| 175 item.SubItems.Add(item.MachineType.ToString()); | |
| 176 item.SubItems.Add(item.SessionId.ToString()); | |
| 177 item.SubItems.Add(item.DisplayCmdLine); | |
| 178 listViewProcesses.Items.Add(item); | |
| 179 } | |
| 180 } | |
| 181 | |
| 182 private void AutoResizeColumns() { | |
| 183 // First adjust to the width of the headers, since it's fast. | |
| 184 listViewProcesses.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize
); | |
| 185 | |
| 186 // Save the widths so we can use them again later. | |
| 187 List<int> widths = new List<int>(); | |
| 188 foreach (ColumnHeader header in listViewProcesses.Columns) | |
| 189 widths.Add(header.Width); | |
| 190 | |
| 191 // Now let Windows do the slow adjustment based on the content. | |
| 192 listViewProcesses.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnCont
ent); | |
| 193 | |
| 194 // Finally, iterate over each column, and resize those columns that just g
ot smaller. | |
| 195 listViewProcesses.Columns[0].Width = 0; | |
| 196 int total = 0; | |
| 197 for (int i = 1; i < listViewProcesses.Columns.Count; ++i) { | |
| 198 // Resize to the largest of the two, but don't let it go over a pre-defi
ned maximum. | |
| 199 int max = Math.Max(listViewProcesses.Columns[i].Width, widths[i]); | |
| 200 int capped = Math.Min(max, 300); | |
| 201 | |
| 202 // We do still want to fill up the available space in the list view howe
ver, so if we're | |
| 203 // under then we can fill. | |
| 204 int globalMinWidth = listViewProcesses.Width - SystemInformation.Vertica
lScrollBarWidth; | |
| 205 if (i == listViewProcesses.Columns.Count - 1 && (total + capped) < (glob
alMinWidth - 4)) | |
| 206 capped = globalMinWidth - total - 4; | |
| 207 | |
| 208 total += capped; | |
| 209 listViewProcesses.Columns[i].Width = capped; | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 private void RepopulateListView() { | |
| 214 listViewProcesses.Items.Clear(); | |
| 215 | |
| 216 ReloadNativeProcessInfo(); | |
| 217 | |
| 218 InsertCategoryItems(ProcessCategory.Browser); | |
| 219 InsertCategoryItems(ProcessCategory.Renderer); | |
| 220 InsertCategoryItems(ProcessCategory.Gpu); | |
| 221 InsertCategoryItems(ProcessCategory.Plugin); | |
| 222 InsertCategoryItems(ProcessCategory.MetroViewer); | |
| 223 InsertCategoryItems(ProcessCategory.Service); | |
| 224 InsertCategoryItems(ProcessCategory.DelegateExecute); | |
| 225 if (!checkBoxOnlyChrome.Checked) | |
| 226 InsertCategoryItems(ProcessCategory.Other); | |
| 227 | |
| 228 AutoResizeColumns(); | |
| 229 } | |
| 230 | |
| 231 private void buttonRefresh_Click(object sender, EventArgs e) { | |
| 232 RepopulateListView(); | |
| 233 } | |
| 234 | |
| 235 private void buttonAttach_Click(object sender, EventArgs e) { | |
| 236 System.Diagnostics.Debug.WriteLine("Closing dialog."); | |
| 237 this.Close(); | |
| 238 } | |
| 239 | |
| 240 private void checkBoxOnlyChrome_CheckedChanged(object sender, EventArgs e) { | |
| 241 if (!checkBoxOnlyChrome.Checked) | |
| 242 InsertCategoryItems(ProcessCategory.Other); | |
| 243 else { | |
| 244 foreach (ProcessViewItem item in loadedProcessTable[ProcessCategory.Othe
r]) { | |
| 245 listViewProcesses.Items.Remove(item); | |
| 246 } | |
| 247 } | |
| 248 } | |
| 249 } | |
| 250 } | |
| OLD | NEW |